Skip to content

Commit

Permalink
优化代码嵌套、代码命名、代码注释
Browse files Browse the repository at this point in the history
修正 Json 提交没有指明长度的问题
修复下载文件过大会导致 UI 抖动的问题
修复下载 MD5 校验失败后同时回调成功和失败的问题
  • Loading branch information
getActivity committed Nov 7, 2020
1 parent c3dc96d commit fa6588d
Show file tree
Hide file tree
Showing 39 changed files with 748 additions and 646 deletions.
Binary file modified EasyHttp.apk
Binary file not shown.
111 changes: 97 additions & 14 deletions HelpDoc.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# 目录

> 文档大致分为三类
* [集成文档](#集成文档)

* [使用文档](#使用文档)
Expand All @@ -23,10 +21,10 @@

#### 关于 Http 明文请求

> Android P 限制了明文流量的网络请求,非加密的流量请求都会被系统禁止掉。
* Android P 限制了明文流量的网络请求,非加密的流量请求都会被系统禁止掉。
如果当前应用的请求是 http 请求,而非 https ,这样就会导系统禁止当前应用进行该请求,如果 WebView 的 url 用 http 协议,同样会出现加载失败,https 不受影响

> 在 res 下新建一个 xml 目录,然后创建一个名为:network_security_config.xml 文件 ,该文件内容如下
* 在 res 下新建一个 xml 目录,然后创建一个名为:network_security_config.xml 文件 ,该文件内容如下

```xml
<?xml version="1.0" encoding="utf-8"?>
Expand All @@ -35,7 +33,7 @@
</network-security-config>
```

> 然后在 AndroidManifest.xml application 标签内应用上面的xml配置
* 然后在 AndroidManifest.xml application 标签内应用上面的xml配置

```xml
<application
Expand Down Expand Up @@ -67,7 +65,7 @@ public class RequestServer implements IRequestServer {

#### 框架初始化

> 需要配置请求结果处理,具体封装可以参考 [RequestHandler](app/src/main/java/com/hjq/http/demo/http/model/RequestHandler.java)
* 需要配置请求结果处理,具体封装可以参考 [RequestHandler](app/src/main/java/com/hjq/http/demo/http/model/RequestHandler.java)

```java
OkHttpClient okHttpClient = new OkHttpClient.Builder()
Expand All @@ -90,13 +88,30 @@ EasyConfig.with(okHttpClient)
.into();
```

> 上述是创建配置,更新配置可以使用
* 上述是创建配置,更新配置可以使用

```java
EasyConfig.getInstance()
.addParam("token", data.getData().getToken());
```

#### 混淆规则

```groovy
# OkHttp3
-keepattributes Signature
-keepattributes *Annotation*
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**
-dontwarn okio.**
# 不混淆这个包下的字段名
-keepclassmembernames class com.hjq.http.demo.http.** {
<fields>;
}
```

# 使用文档

#### 配置接口
Expand Down Expand Up @@ -142,10 +157,18 @@ public final class LoginApi implements IRequestApi {
* implements IRequestPath:实现这个接口之后可以重新指定这个请求的接口路径

* implements IRequestType:实现这个接口之后可以重新指定这个请求的提交方式

* 字段作为请求参数的衡量标准

* 假设某个字段的属性值为空,那么这个字段将不会作为请求参数发送给后台

* 假设果某个字段类型是 String,属性值是空字符串,那么这个字段就会作为请求参数,如果是空对象则不会

* 假设某个字段类型是 int,因为基本数据类型没有空值,所以这个字段一定会作为请求参数,但是可以换成 Integer 对象来避免,因为 Integer 的默认值是 null

#### 发起请求

> 需要配置请求状态及生命周期处理,具体封装可以参考 [BaseActivity](app/src/main/java/com/hjq/http/demo/BaseActivity.java)
* 需要配置请求状态及生命周期处理,具体封装可以参考 [BaseActivity](app/src/main/java/com/hjq/http/demo/BaseActivity.java)

```java
EasyHttp.post(this)
Expand All @@ -161,8 +184,38 @@ EasyHttp.post(this)
});
```

* 这里展示 post 用法,另外 EasyHttp 还支持 get、head、delete、put、patch 请求方式,这里不再过多演示

#### 上传文件

```java
public final class UpdateImageApi implements IRequestApi, IRequestType {

@Override
public String getApi() {
return "upload/";
}

@Override
public BodyType getType() {
// 上传文件需要使用表单的形式提交
return BodyType.FORM;
}

/** 本地图片 */
private File image;

public UpdateImageApi(File image) {
this.image = image;
}

public UpdateImageApi setImage(File image) {
this.image = image;
return this;
}
}
```

```java
EasyHttp.post(this)
.api(new UpdateImageApi(file))
Expand All @@ -174,7 +227,7 @@ EasyHttp.post(this)
}

@Override
public void onUpdate(long totalByte, long updateByte, int progress) {
public void onProgress(int progress) {
mProgressBar.setProgress(progress);
}

Expand All @@ -197,7 +250,7 @@ EasyHttp.post(this)

#### 下载文件

> 下载缓存策略:在指定下载文件 md5 或者后台有返回 md5 的情况下,下载框架默认开启下载缓存模式,如果这个文件已经存在手机中,并且经过 md5 校验文件完整,框架就不会重复下载,而是直接回调下载监听。减轻服务器压力,减少用户等待时间。
* 下载缓存策略:在指定下载文件 md5 或者后台有返回 md5 的情况下,下载框架默认开启下载缓存模式,如果这个文件已经存在手机中,并且经过 md5 校验文件完整,框架就不会重复下载,而是直接回调下载监听。减轻服务器压力,减少用户等待时间。

```java
EasyHttp.download(this)
Expand All @@ -214,7 +267,7 @@ EasyHttp.download(this)
}

@Override
public void onProgress(File file, long totalByte, long downloadByte, int progress) {
public void onProgress(File file, int progress) {
mProgressBar.setProgress(progress);
}

Expand Down Expand Up @@ -244,7 +297,7 @@ try {
HttpData<SearchBean> data = EasyHttp.post(MainActivity.this)
.api(new SearchBlogsApi()
.setKeyword("搬砖不再有"))
.execute(new DataClass<HttpData<SearchBean>>() {});
.execute(new ResponseClass<HttpData<SearchBean>>() {});
ToastUtils.show("请求成功,请看日志");
} catch (Exception e) {
e.printStackTrace();
Expand Down Expand Up @@ -582,7 +635,7 @@ EasyConfig.getInstance().setLogEnabled(false);

#### 框架指定只能传入 LifecycleOwner,我想传入其他对象怎么办?

* 其中 AppCompatActivity 和 AndroidX.Fragment 都是 LifecycleOwner 子类的,这个是毋庸置疑的
* 其中 AndroidX.AppCompatActivity 和 AndroidX.Fragment 都是 LifecycleOwner 子类的,这个是毋庸置疑的

* 但是你如果传入的是 Activity 对象,并非 AppCompatActivity 对象,那么你可以这样写

Expand Down Expand Up @@ -628,4 +681,34 @@ EasyHttp.cancel(LifecycleOwner lifecycleOwner);
EasyHttp.cancel(Object tag);
// 取消所有请求
EasyHttp.cancel();
```
```

#### getHost、getPath、getApi 方法之间的作用和区别?

* Host:服务器主机的地址

* Path:除主机地址之外的路径

* Api:业务模块地址

* 我举个栗子:[https://www.baidu.com/api/user/getInfo](https://www.baidu.com/),那么标准的写法就是

```java
public final class XxxApi implements IRequestServer, IRequestApi {

@Override
public String getHost() {
return "https://www.baidu.com/";
}

@Override
public String getPath() {
return "api/";
}

@Override
public String getApi() {
return "user/getInfo";
}
}
```
64 changes: 37 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
# 网络请求框架
# 简单易用的网络框架

> 码云地址:[Gitee](https://gitee.com/getActivity/EasyHttp)
> [点击此处下载Demo](EasyHttp.apk)
![](EasyHttp.jpg)

> 另外对 OkHttp 源码感兴趣的同学可以看下面几篇文章
* [OkHttp 精讲:拦截器执行原理](https://www.jianshu.com/p/e0f324fd9411)

* [OkHttp 精讲:RetryAndFollowUpInterceptor](https://www.jianshu.com/p/40636d32cb67)

* [OkHttp 精讲:BridgeInterceptor](https://www.jianshu.com/p/fab2d74de900)

* [OkHttp 精讲:CacheInterceptor](https://www.jianshu.com/p/44fad764c0ae)

* [OkHttp 精讲:ConnectInterceptor](https://www.jianshu.com/p/a3a774fdff4f)

* [OkHttp 精讲:CallServerInterceptor](https://www.jianshu.com/p/aa77af6251ff)

#### Gradle 集成

```groovy
Expand All @@ -18,61 +32,57 @@ android {
}
dependencies {
implementation 'com.hjq:http:8.6'
// 网络请求框架:https://github.com/getActivity/EasyHttp
implementation 'com.hjq:http:8.8'
// OkHttp 框架:https://github.com/square/okhttp
// noinspection GradleDependency
implementation 'com.squareup.okhttp3:okhttp:3.12.12'
implementation 'com.google.code.gson:gson:2.8.5'
}
```
#### 具体用法[请点击这里查看](HelpDoc.md)
## [框架的具体用法请点击这里查看](HelpDoc.md)

#### 不同网络请求框架之间的对比

| 功能 | [EasyHttp](https://github.com/getActivity/EasyHttp) | [Retrofit](https://github.com/square/retrofit) | [OkGo](https://github.com/jeasonlzy/okhttp-OkGo) |
| :----: | :------: | :-----: | :-----: |
| 对应版本 | 8.8 | 2.9.0 | 3.0.4 |
| 动态 Host | 支持 | 不支持 | 支持 |
| 全局参数 | 支持 | 不支持 | 支持 |
| 超时重试 | 支持 | 不支持 | 支持 |
| 极速下载 | 支持 | 不支持 | 不支持 |
| 下载校验 | 支持 | 不支持 | 不支持 |
| 极速下载 | 支持 | 不支持 | 不支持 |
| 注解数量 | 3 个 | 25 个 | 0 个 |
| 上传文件类型 | File / InputStream | RequestBody | File |
| 上传文件类型 | File / InputStream / RequestBody | RequestBody | File |
| 批量上传文件 | 支持 | 不支持 | 支持 |
| 上传进度监听 | 支持 | 不支持 | 支持 |
| Json 参数提交 | 支持 | 支持 | 支持 |
| Json 参数提交 | 支持 | 不支持 | 支持 |
| 请求生命周期 | 自动管控 | 需要封装 | 需要封装 |
| 参数传值方式 | 字段名 + 字段值 | 方法参数名 + 方法参数值 | 定义 key 和 value |
| 参数传值方式 | 字段名 + 字段值 | 方法参数名 + 方法参数值 | 定义 Key + Value |
| 参数灵活性 | 不强制传入 | 强制全部传入 | 不强制传入 |
| 自定义 RequestBody | 支持 | 支持 | 支持 |
| minSdk 要求 | API 14+ | API 21+ | API 14+ |
| class 文件数量 | 70 个 | 54 个 | 85 个 |
| aar 包大小 | [55 KB](https://bintray.com/getactivity/maven/http#files/com/hjq/http) | [123 KB](https://bintray.com/bintray/jcenter/com.squareup.retrofit2%3Aretrofit#files) | [131 KB](https://bintray.com/jeasonlzy/maven/okgo#files/com/lzy/net/okgo) |
| 框架维护状态 | 维护中 | 维护中 | 停止维护 |

* Retrofit 在我看来并不是那么好用,因为很多常用的功能实现起来比较麻烦,动态 Host 要写拦截器,日志打印要写拦截器,就连最常用的添加全局参数也要写拦截器,一个拦截器意味着要写很多代码,如果写得不够严谨还有可能出现 Bug,从而影响整个 OkHttp 请求流程,我经常在想这些功能能不能都用一句代码搞定,因为我觉得这些功能是框架设计的时候应该考虑的,这便是我做这个框架的初心。
* Retrofit 在我看来并不是那么好用,因为很多常用的功能实现起来比较麻烦,动态 Host 要写拦截器,日志打印要写拦截器,就连最常用的添加全局参数也要写拦截器,一个拦截器意味着要写很多代码,如果写得不够严谨还有可能出现 Bug,从而影响整个 OkHttp 请求流程,我经常在想这些功能能不能都用一句代码搞定,因为我觉得这些功能是设计框架的时候本应该考虑的,这便是我做这个框架的初心。

* 本框架采用了 OOP 思想,一个请求代表一个对象,通过类的继承和实现的特性来实现接口的动态化,几乎涵盖接口开发中所有的功能,使用起来非常简单灵活。
* 本框架采用了 OOP 思想,一个请求代表一个对象,通过类的继承和实现的特性来实现接口的动态化配置,几乎涵盖接口开发中所有的功能,使用起来非常简单灵活。

* 有很多人觉得写一个接口类很麻烦,这个点确实有点麻烦,但是这块的付出是有收获的,从前期开发的效率考虑:OkGo > EasyHttp > Retrofit,但是从后期维护的效率考虑:EasyHttp > Retrofit > OkGo,之所以比较这三个框架,是因为框架的设计思想不同,但是我始终认为 EasyHttp 才是最好的设计,所以我创造了它。

* 前期开发和后期维护哪个更重要?我觉得都重要,但是如果两者之间有利益冲突,我会毫不犹豫选择后期维护,因为前期开发占据的是小头,后期的持续维护才是大头。
* 前期开发和后期维护哪个更重要?我觉得都重要,但是如果两者之间存在利益冲突,我会毫不犹豫地选择后期维护,因为前期开发占据的是小头,后期的持续维护才是大头。

#### 混淆规则
#### 极速下载功能介绍

```groovy
# OkHttp3
-keepattributes Signature
-keepattributes *Annotation*
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**
-dontwarn okio.**
# 不混淆这个包下的字段名
-keepclassmembernames class com.hjq.http.demo.http.** {
<fields>;
}
```
* 其实本质上面和极速秒传的原理是差不多的,只不过一个是上传,一个是下载。而极速上传是将本地文件的 MD5 值和服务器上面的进行比对,如果服务器存在这个 MD5 值的文件,就将这份文件映射一份到这个用户的网盘上面,从而达到了极速秒传的效果。而极速下载也是同理,根据后台给的文件 MD5 值和本地文件进行对比,如果存在这个文件并且 MD5 值一致,证明这个文件和服务器上面的文件是一致的,那么就直接跳过下载,直接回调下载成功监听。

* 极速秒传和极速下载两者相同的共同点就是,利用缓存来达到极速的效果,只不过一者通过的是服务器的缓存,另一者使用的是本地的缓存,这两者都有一个共同的特点,就是减少服务器的压力,节省用户的等待时间。

#### 作者的其他开源项目

* 安卓架构[AndroidProject](https://github.com/getActivity/AndroidProject)
* 安卓技术中台[AndroidProject](https://github.com/getActivity/AndroidProject)

* 日志框架:[Logcat](https://github.com/getActivity/Logcat)

Expand Down
17 changes: 9 additions & 8 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ android {
}

defaultConfig {
applicationId "com.hjq.http.demo"
minSdkVersion 14
applicationId 'com.hjq.http.demo'
minSdkVersion 16
targetSdkVersion 30
versionCode 86
versionName "8.6"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
versionCode 88
versionName '8.8'
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}

buildTypes {
Expand Down Expand Up @@ -49,16 +49,17 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.3.0-alpha02'

// 标题栏:https://github.com/getActivity/TitleBar
implementation 'com.hjq:titlebar:8.0'
implementation 'com.hjq:titlebar:8.2'
// 吐司工具类:https://github.com/getActivity/ToastUtils
implementation 'com.hjq:toast:8.8'
// 权限请求框架:https://github.com/getActivity/XXPermissions
implementation 'com.hjq:xxpermissions:8.8'
implementation 'com.hjq:xxpermissions:9.2'
// Json 解析框架:https://github.com/google/gson
implementation 'com.google.code.gson:gson:2.8.5'
// OkHttp 框架:https://github.com/square/okhttp
// 升级注意事项:https://www.jianshu.com/p/d12d0f536f55
// noinspection GradleDependency
implementation 'com.squareup.okhttp3:okhttp:3.12.12'
// 日志调试:https://github.com/getActivity/Logcat
debugImplementation 'com.hjq:logcat:8.6'
debugImplementation 'com.hjq:logcat:9.0'
}
Loading

0 comments on commit fa6588d

Please sign in to comment.