Skip to content

Commit a7773b6

Browse files
committed
新增 Protobuf 相关使用文档
优化框架中相关 RequestBody 类命名 优化框架中代码嵌套逻辑及日志打印逻辑 修正框架抛 Exception 成抛 Throwable 对象 修正 Post Json RequestBody 日志打印显示错误的问题
1 parent bce64a1 commit a7773b6

39 files changed

+546
-319
lines changed

HelpDoc.md

Lines changed: 235 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,14 @@
112112

113113
* [对返回的数据进行包装](#对返回的数据进行包装)
114114

115+
* [支持 Protobuf](#支持-protobuf)
116+
117+
* [准备工作](#准备工作)
118+
119+
* [请求体解析成 Protobuf](#请求体解析成-protobuf)
120+
121+
* [响应体解析支持 Protobuf](#响应体解析支持-protobuf)
122+
115123
# 集成文档
116124

117125
#### 配置权限
@@ -365,7 +373,7 @@ EasyHttp.post(this)
365373
}
366374

367375
@Override
368-
public void onUpdateFail(Exception e) {
376+
public void onUpdateFail(Throwable throwable) {
369377
toast("上传失败");
370378
}
371379

@@ -410,8 +418,8 @@ EasyHttp.download(this)
410418
}
411419

412420
@Override
413-
public void onDownloadFail(File file, Exception e) {
414-
toast("下载出错:" + e.getMessage());
421+
public void onDownloadFail(File file, Throwable throwable) {
422+
toast("下载出错:" + throwable.getMessage());
415423
}
416424

417425
@Override
@@ -465,8 +473,8 @@ try {
465473
.setKeyword("搬砖不再有"))
466474
.execute(new ResponseClass<HttpData<SearchBean>>() {});
467475
toast("请求成功,请看日志");
468-
} catch (Exception e) {
469-
toast(e.getMessage());
476+
} catch (Throwable throwable) {
477+
toast(throwable.getMessage());
470478
}
471479
```
472480

@@ -647,8 +655,8 @@ lifecycleScope.launch(Dispatchers.IO) {
647655
withContext(Dispatchers.Main) {
648656
// 在这里进行 UI 刷新
649657
}
650-
} catch (e: Exception) {
651-
toast(e.message)
658+
} catch (throwable: Throwable) {
659+
toast(throwable.message)
652660
}
653661
}
654662
```
@@ -991,6 +999,8 @@ public final class XxxApi implements IRequestApi {
991999

9921000
#### 如何传入请求头
9931001

1002+
* 给字段加上 `@HttpHeader` 注解即可,则表示这个字段是一个请求头,如果没有加上此注解,则框架默认将字段作为请求参数
1003+
9941004
```java
9951005
public final class XxxApi implements IRequestApi {
9961006

@@ -1007,6 +1017,8 @@ public final class XxxApi implements IRequestApi {
10071017

10081018
#### 如何重命名参数或者请求头的名称
10091019

1020+
* 给字段加上 `@HttpRename` 注解即可,则可以修改参数名的值,如果没有加上此注解,则框架默认使用字段名作为参数名
1021+
10101022
```java
10111023
public final class XxxApi implements IRequestApi {
10121024

@@ -1156,12 +1168,12 @@ EasyConfig.with(okHttpClient)
11561168
#### 如何取消已发起的请求
11571169

11581170
```java
1159-
// 取消和这个 LifecycleOwner 关联的请求
1160-
EasyHttp.cancel(LifecycleOwner lifecycleOwner);
1171+
// 根据 TAG 取消请求任务
1172+
EasyHttp.cancelByTag(Object tag);
11611173
// 取消指定 Tag 标记的请求
1162-
EasyHttp.cancel(Object tag);
1174+
EasyHttp.cancelByTag(Object tag);
11631175
// 取消所有请求
1164-
EasyHttp.cancel();
1176+
EasyHttp.cancelAll();
11651177
```
11661178

11671179
#### 如何延迟发起一个请求
@@ -1296,7 +1308,7 @@ EasyHttp.post(ApplicationLifecycle.getInstance())
12961308
}
12971309

12981310
@Override
1299-
public void onHttpFail(Exception e) {
1311+
public void onHttpFail(Throwable throwable) {
13001312

13011313
}
13021314
});
@@ -1307,7 +1319,7 @@ EasyHttp.post(ApplicationLifecycle.getInstance())
13071319
* 除了 Application,如果你在 Activity 或者 Service 中采用了 ApplicationLifecycle 的写法,那么为了避免内存泄漏或者崩溃的事情发生,需要你在请求的时候设置对应的 Tag,然后在恰当的时机手动取消请求(一般在 Activity 或者 Service 销毁或者退出的时候取消请求)。
13081320

13091321
```java
1310-
EasyHttp.cancel("abc");
1322+
EasyHttp.cancelByTag("abc");
13111323
```
13121324

13131325
#### 如何在 ViewModel 中使用 EasyHttp 请求网络
@@ -1354,7 +1366,7 @@ public class XxxViewModel extends BaseViewModel {
13541366
}
13551367

13561368
@Override
1357-
public void onHttpFail(Exception e) {
1369+
public void onHttpFail(Throwable throwable) {
13581370

13591371
}
13601372
});
@@ -1401,7 +1413,7 @@ EasyHttp.post(this)
14011413
}
14021414

14031415
@Override
1404-
public void onHttpFail(Exception e) {
1416+
public void onHttpFail(Throwable throwable) {
14051417

14061418
}
14071419
});
@@ -1419,7 +1431,7 @@ String json = gson.toJson(parameter);
14191431

14201432
EasyHttp.post(this)
14211433
.api(new XxxApi())
1422-
.body(new JsonBody(json))
1434+
.body(new JsonRequestBody(json))
14231435
.request(new HttpCallbackProxy<HttpData<Xxx>>(this) {
14241436

14251437
@Override
@@ -1450,11 +1462,11 @@ parameter.put("key1", value1);
14501462
parameter.put("key2", value2);
14511463

14521464
String json = gson.toJson(parameter);
1453-
JsonBody jsonBody = new JsonBody(json)
1465+
JsonRequestBody jsonRequestBody = new JsonRequestBody(json)
14541466

14551467
EasyHttp.post(this)
14561468
.api(new XxxApi())
1457-
.body(jsonBody)
1469+
.body(jsonRequestBody)
14581470
.request(new HttpCallbackProxy<HttpData<Xxx>>(this) {
14591471

14601472
@Override
@@ -1655,8 +1667,12 @@ Observable.create(new ObservableOnSubscribe<HttpData<SearchBean>>() {
16551667
.api(new SearchBlogsApi()
16561668
.setKeyword("搬砖不再有"))
16571669
.execute(new ResponseClass<HttpData<SearchBean>>() {});
1658-
} catch (Exception e) {
1659-
throw e;
1670+
} catch (Throwable throwable) {
1671+
if (throwable instanceof Exception) {
1672+
throw (Exception) throwable;
1673+
} else {
1674+
throw new RuntimeException(throwable);
1675+
}
16601676
}
16611677

16621678
HttpData<SearchBean> data2;
@@ -1665,8 +1681,12 @@ Observable.create(new ObservableOnSubscribe<HttpData<SearchBean>>() {
16651681
.api(new SearchBlogsApi()
16661682
.setKeyword(data1.getMessage()))
16671683
.execute(new ResponseClass<HttpData<SearchBean>>() {});
1668-
} catch (Exception e) {
1669-
throw e;
1684+
} catch (Throwable throwable) {
1685+
if (throwable instanceof Exception) {
1686+
throw (Exception) throwable;
1687+
} else {
1688+
throw new RuntimeException(throwable);
1689+
}
16701690
}
16711691

16721692
emitter.onNext(data2);
@@ -1740,9 +1760,9 @@ Observable.create(new ObservableOnSubscribe<HttpData<SearchBean>>() {
17401760
}
17411761

17421762
@Override
1743-
public void onHttpFail(Exception e) {
1744-
super.onHttpFail(e);
1745-
emitter.onError(e);
1763+
public void onHttpFail(Throwable throwable) {
1764+
super.onHttpFail(throwable);
1765+
emitter.onError(throwable);
17461766
}
17471767
});
17481768
}
@@ -1764,7 +1784,7 @@ Observable.create(new ObservableOnSubscribe<HttpData<SearchBean>>() {
17641784

17651785
@Override
17661786
public void accept(String s) throws Exception {
1767-
Log.i("EasyHttp", ""当前页码位置" + s);
1787+
Log.i("EasyHttp", "当前页码位置" + s);
17681788
}
17691789

17701790
}, new Consumer<Throwable>() {
@@ -1774,4 +1794,193 @@ Observable.create(new ObservableOnSubscribe<HttpData<SearchBean>>() {
17741794
toast(throwable.getMessage());
17751795
}
17761796
});
1797+
```
1798+
1799+
# 支持 Protobuf
1800+
1801+
#### 准备工作
1802+
1803+
* 在项目根目录下得 `build.gradle` 文件加入以下配置
1804+
1805+
```groovy
1806+
buildscript {
1807+
1808+
......
1809+
1810+
dependencies {
1811+
// 自动生成 Protobuf 类插件:https://github.com/google/protobuf-gradle-plugin
1812+
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.9.3'
1813+
}
1814+
}
1815+
```
1816+
1817+
* 在项目 app 模块下的 `build.gradle` 文件中加入远程依赖
1818+
1819+
```groovy
1820+
......
1821+
1822+
apply plugin: 'com.google.protobuf'
1823+
1824+
android {
1825+
......
1826+
1827+
sourceSets {
1828+
main {
1829+
proto {
1830+
// 指定 Protobuf 文件路径
1831+
srcDir 'src/main/proto'
1832+
}
1833+
}
1834+
}
1835+
}
1836+
1837+
protobuf {
1838+
1839+
protoc {
1840+
// 也可以配置本地编译器路径
1841+
artifact = 'com.google.protobuf:protoc:3.23.0'
1842+
}
1843+
1844+
generateProtoTasks {
1845+
all().each { task ->
1846+
task.builtins {
1847+
remove java
1848+
}
1849+
task.builtins {
1850+
// 生产java源码
1851+
java {}
1852+
}
1853+
}
1854+
}
1855+
}
1856+
1857+
dependencies {
1858+
1859+
......
1860+
1861+
// Protobuf:https://github.com/protocolbuffers/protobuf
1862+
implementation 'com.google.protobuf:protobuf-java:3.23.1'
1863+
implementation 'com.google.protobuf:protoc:3.23.0'
1864+
}
1865+
```
1866+
1867+
*`app/src/main/` 新建一个名为 `proto` 文件夹,用于存放 Protobuf 相关文件,然后创建 `Person.proto` 文件,具体内容如下:
1868+
1869+
```text
1870+
syntax = "proto3";
1871+
package tutorial;
1872+
1873+
message Person {
1874+
string name = 1;
1875+
int32 id = 2;
1876+
string email = 3;
1877+
string phone = 4;
1878+
}
1879+
```
1880+
1881+
* 然后 `Rebuild Project`,就能看到插件自动生成的 `PersonOuterClass` 类,`PersonOuterClass` 类中还有一个名为 `Person` 的静态内部类
1882+
1883+
#### 请求体解析成 Protobuf
1884+
1885+
* 创建一个自定义的 RequestBody 类,用于将 Protocol 对象解析成流,建议存放在 `com.xxx.xxx/http/model` 包名下,
1886+
1887+
```java
1888+
public class ProtocolRequestBody extends RequestBody {
1889+
1890+
/** MessageLite 对象 */
1891+
private final MessageLite mMessageLite;
1892+
/** 字节数组 */
1893+
private final byte[] mBytes;
1894+
1895+
public ProtocolRequestBody(MessageLite messageLite) {
1896+
mMessageLite = messageLite;
1897+
mBytes = messageLite.toByteArray();
1898+
}
1899+
1900+
@Override
1901+
public MediaType contentType() {
1902+
return ContentType.JSON;
1903+
}
1904+
1905+
@Override
1906+
public long contentLength() {
1907+
// 需要注意:这里需要用字节数组的长度来计算
1908+
return mBytes.length;
1909+
}
1910+
1911+
@Override
1912+
public void writeTo(BufferedSink sink) throws IOException {
1913+
sink.write(mBytes, 0, mBytes.length);
1914+
}
1915+
1916+
@NonNull
1917+
@Override
1918+
public String toString() {
1919+
return mMessageLite.toString();
1920+
}
1921+
1922+
/**
1923+
* 获取 MessageLite 对象
1924+
*/
1925+
@NonNull
1926+
public MessageLite getMessageLite() {
1927+
return mMessageLite;
1928+
}
1929+
}
1930+
```
1931+
1932+
* 发起请求示例
1933+
1934+
```java
1935+
// 假装生成一个 Protobuf 对象
1936+
Person person = Person.parseFrom("xxxxxxxxx".getBytes());
1937+
1938+
EasyHttp.post(this)
1939+
.api(new XxxApi())
1940+
.body(new ProtocolRequestBody(person))
1941+
.request(new HttpCallbackProxy<HttpData<SearchBlogsApi.Bean>>(this) {
1942+
1943+
@Override
1944+
public void onHttpSuccess(HttpData<SearchBlogsApi.Bean> result) {
1945+
1946+
}
1947+
});
1948+
```
1949+
1950+
#### 响应体解析支持 Protobuf
1951+
1952+
* 这个支持很简单了,只需要修改 `IRequestHandler` 接口的实现即可,具体的代码实现如下:
1953+
1954+
```
1955+
public final class RequestHandler implements IRequestHandler {
1956+
1957+
......
1958+
1959+
@NonNull
1960+
@Override
1961+
public Object requestSuccess(@NonNull HttpRequest<?> httpRequest, @NonNull Response response,
1962+
@NonNull Type type) throws Throwable {
1963+
......
1964+
1965+
final Object result;
1966+
1967+
try {
1968+
if (type instanceof Class<?> && AbstractParser.class.isAssignableFrom((Class<?>) type)) {
1969+
String simpleName = ((Class<?>) type).getSimpleName();
1970+
Class<?> clazz = Class.forName("tutorial." + simpleName + ".OuterClass." + simpleName);
1971+
Method parseFromMethod = clazz.getMethod("parseFrom", byte[].class);
1972+
// 调用静态方法
1973+
result = parseFromMethod.invoke(null, (Object) text.getBytes());
1974+
} else {
1975+
result = GsonFactory.getSingletonGson().fromJson(text, type);
1976+
}
1977+
} catch (JsonSyntaxException e) {
1978+
// 返回结果读取异常
1979+
throw new DataException(mApplication.getString(R.string.http_data_explain_error), e);
1980+
}
1981+
1982+
......
1983+
return result;
1984+
}
1985+
}
17771986
```

0 commit comments

Comments
 (0)