diff --git a/EasyHttp.apk b/EasyHttp.apk
index a82c03b..2ea264c 100644
Binary files a/EasyHttp.apk and b/EasyHttp.apk differ
diff --git a/EasyHttp.jpg b/EasyHttp.jpg
index 9b3fed7..fd756ba 100644
Binary files a/EasyHttp.jpg and b/EasyHttp.jpg differ
diff --git a/HelpDoc.md b/HelpDoc.md
index 5ed841f..a7acaf7 100644
--- a/HelpDoc.md
+++ b/HelpDoc.md
@@ -1,10 +1,266 @@
+# 目录
+
+> 文档大致分为三类
+
+* [集成文档](#集成文档)
+
+* [使用文档](#使用文档)
+
+* [疑难解答](#疑难解答)
+
+# 集成文档
+
+#### 配置权限
+
+```xml
+
+
+
+
+
+
+```
+
+#### 关于 Http 明文请求
+
+> Android P 限制了明文流量的网络请求,非加密的流量请求都会被系统禁止掉。
+如果当前应用的请求是 http 请求,而非 https ,这样就会导系统禁止当前应用进行该请求,如果 WebView 的 url 用 http 协议,同样会出现加载失败,https 不受影响
+
+> 在 res 下新建一个 xml 目录,然后创建一个名为:network_security_config.xml 文件 ,该文件内容如下
+
+```xml
+
+
+
+
+```
+
+> 然后在 AndroidManifest.xml application 标签内应用上面的xml配置
+
+```xml
+
+```
+
+#### 服务器配置
+
+```java
+public class RequestServer implements IRequestServer {
+
+ @Override
+ public String getHost() {
+ return "https://www.baidu.com/";
+ }
+
+ @Override
+ public String getPath() {
+ return "api/";
+ }
+
+ @Override
+ public BodyType getType() {
+ // 参数以 Json 格式提交(默认是表单)
+ return BodyType.JSON;
+ }
+}
+```
+
+#### 框架初始化
+
+> 需要配置请求结果处理,具体封装可以参考 [RequestHandler](app/src/main/java/com/hjq/http/demo/http/model/RequestHandler.java)
+
+```java
+OkHttpClient okHttpClient = new OkHttpClient.Builder()
+ .build();
+
+EasyConfig.with(okHttpClient)
+ // 是否打印日志
+ .setLogEnabled(BuildConfig.DEBUG)
+ // 设置服务器配置
+ .setServer(server)
+ // 设置请求处理策略
+ .setHandler(new RequestHandler())
+ // 设置请求重试次数
+ .setRetryCount(3)
+ // 添加全局请求参数
+ //.addParam("token", "6666666")
+ // 添加全局请求头
+ //.addHeader("time", "20191030")
+ // 启用配置
+ .into();
+```
+
+> 上述是创建配置,更新配置可以使用
+
+```java
+EasyConfig.getInstance()
+ .addParam("token", data.getData().getToken());
+```
+
+# 使用文档
+
+#### 配置接口
+
+```java
+public final class LoginApi implements IRequestApi {
+
+ @Override
+ public String getApi() {
+ return "user/login";
+ }
+
+ /** 用户名 */
+ private String userName;
+
+ /** 登录密码 */
+ private String password;
+
+ public LoginApi setUserName(String userName) {
+ this.userName = userName;
+ return this;
+ }
+
+ public LoginApi setPassword(String password) {
+ this.password = password;
+ return this;
+ }
+}
+```
+
+* 可为这个类的字段加上一些注解
+
+ * @HttpHeader:标记这个字段是一个请求头参数
+
+ * @HttpIgnore:标记这个字段不会被发送给后台
+
+ * @HttpRename:重新定义这个字段发送给后台的参数名称
+
+* 可在这个类实现一些接口
+
+ * implements IRequestHost:实现这个接口之后可以重新指定这个请求的主机地址
+
+ * implements IRequestPath:实现这个接口之后可以重新指定这个请求的接口路径
+
+ * implements IRequestType:实现这个接口之后可以重新指定这个请求的提交方式
+
+#### 发起请求
+
+> 需要配置请求状态及生命周期处理,具体封装可以参考 [BaseActivity](app/src/main/java/com/hjq/http/demo/BaseActivity.java)
+
+```java
+EasyHttp.post(this)
+ .api(new LoginApi()
+ .setUserName("Android 轮子哥")
+ .setPassword("123456"))
+ .request(new HttpCallback>(activity) {
+
+ @Override
+ public void onSucceed(HttpData data) {
+ ToastUtils.show("登录成功");
+ }
+ });
+```
+
+#### 上传文件
+
+```java
+EasyHttp.post(this)
+ .api(new UpdateImageApi(file))
+ .request(new OnUpdateListener() {
+
+ @Override
+ public void onStart(Call call) {
+ mProgressBar.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void onUpdate(long totalByte, long updateByte, int progress) {
+ mProgressBar.setProgress(progress);
+ }
+
+ @Override
+ public void onSucceed(Void result) {
+ ToastUtils.show("上传成功");
+ }
+
+ @Override
+ public void onFail(Exception e) {
+ ToastUtils.show("上传失败");
+ }
+
+ @Override
+ public void onEnd(Call call) {
+ mProgressBar.setVisibility(View.GONE);
+ }
+ });
+```
+
+#### 下载文件
+
+> 下载缓存策略:在指定下载文件 md5 或者后台有返回 md5 的情况下,下载框架默认开启下载缓存模式,如果这个文件已经存在手机中,并且经过 md5 校验文件完整,框架就不会重复下载,而是直接回调下载监听。减轻服务器压力,减少用户等待时间。
+
+```java
+EasyHttp.download(this)
+ .method(HttpMethod.GET)
+ .file(new File(Environment.getExternalStorageDirectory(), "微信.apk"))
+ //.url("https://qd.myapp.com/myapp/qqteam/AndroidQQ/mobileqq_android.apk")
+ .url("http://dldir1.qq.com/weixin/android/weixin708android1540.apk")
+ .md5("2E8BDD7686474A7BC4A51ADC3667CABF")
+ .listener(new OnDownloadListener() {
+
+ @Override
+ public void onStart(File file) {
+ mProgressBar.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void onProgress(File file, long totalByte, long downloadByte, int progress) {
+ mProgressBar.setProgress(progress);
+ }
+
+ @Override
+ public void onComplete(File file) {
+ ToastUtils.show("下载完成:" + file.getPath());
+ installApk(MainActivity.this, file);
+ }
+
+ @Override
+ public void onError(File file, Exception e) {
+ ToastUtils.show("下载出错:" + e.getMessage());
+ }
+
+ @Override
+ public void onEnd(File file) {
+ mProgressBar.setVisibility(View.GONE);
+ }
+
+ }).start();
+```
+
+#### 同步请求
+
+```java
+try {
+ HttpData data = EasyHttp.post(MainActivity.this)
+ .api(new SearchBlogsApi()
+ .setKeyword("搬砖不再有"))
+ .execute(new DataClass>() {});
+ ToastUtils.show("请求成功,请看日志");
+} catch (Exception e) {
+ e.printStackTrace();
+ ToastUtils.show(e.getMessage());
+}
+```
+
+# 疑难解答
+
#### 如何添加全局参数?
```java
// 添加全局请求参数
-EasyConfig.getInstance().addHeader("token", "abc");
-// 添加全局请求头
EasyConfig.getInstance().addParam("token", "abc");
+// 添加全局请求头
+EasyConfig.getInstance().addHeader("token", "abc");
```
#### 如何定义全局的动态参数?
@@ -149,14 +405,29 @@ public class XxxServer implements IRequestServer {
}
```
-* 当然也支持对某个接口进行单独配置,和上个问题雷同,这里略过
+* 当然也支持对某个接口进行单独配置
+
+```java
+public final class XxxApi implements IRequestApi, IRequestType {
+
+ @Override
+ public String getApi() {
+ return "xxx/xxxx";
+ }
+
+ @Override
+ public BodyType getType() {
+ return BodyType.JSON;
+ }
+}
+```
* 表单和 Json 方式提交的优缺点对比
| 场景 | 表单方式 | Json 方式 |
| :----: | :------: | :-----: |
-| 参数嵌套 | 不支持 | 支持 |
-| 文件上传 | 支持 | 不支持 |
+| 参数嵌套 | 不支持 | 支持 |
+| 文件上传 | 支持 | 不支持 |
#### 如何忽略某个参数?
@@ -264,11 +535,97 @@ public final class XxxApi implements IRequestApi {
#### 如何设置超时重试?
```java
+// 设置请求重试次数
EasyConfig.getInstance().setRetryCount(3);
+// 设置请求重试时间
+EasyConfig.getInstance().setRetryTime(1000);
+```
+
+#### 如何设置请求超时时间?
+
+* 全局配置(所有接口都生效)
+
+```java
+OkHttpClient.Builder builder = new OkHttpClient.Builder();
+builder.readTimeout(5000, TimeUnit.MILLISECONDS);
+builder.writeTimeout(5000, TimeUnit.MILLISECONDS);
+builder.connectTimeout(5000, TimeUnit.MILLISECONDS);
+EasyConfig.with(builder.build())
+ .into();
+```
+
+* 局部配置(只在某个请求生效)
+
+```java
+OkHttpClient.Builder builder = EasyConfig.getInstance().getClient().newBuilder();
+builder.readTimeout(5000, TimeUnit.MILLISECONDS);
+builder.writeTimeout(5000, TimeUnit.MILLISECONDS);
+builder.connectTimeout(5000, TimeUnit.MILLISECONDS);
+
+EasyHttp.post(this)
+ .api(new XxxApi())
+ .client(builder.build())
+ .request(new HttpCallback>(this) {
+
+ @Override
+ public void onSucceed(HttpData data) {
+
+ }
+ });
```
#### 如何设置不打印日志?
```java
EasyConfig.getInstance().setLogEnabled(false);
+```
+
+#### 框架指定只能传入 LifecycleOwner,我想传入其他对象怎么办?
+
+* 其中 AppCompatActivity 和 AndroidX.Fragment 都是 LifecycleOwner 子类的,这个是毋庸置疑的
+
+* 但是你如果传入的是 Activity 对象,并非 AppCompatActivity 对象,那么你可以这样写
+
+```java
+EasyHttp.post(new ActivityLifecycle(this))
+ .api(new XxxApi())
+ .request(new HttpCallback>(this) {
+
+ @Override
+ public void onSucceed(HttpData result) {
+
+ }
+ });
+```
+
+* 如果以上条件都不满足,但是你就是想在某个地方请求网络,那么你可以这样写
+
+```java
+EasyHttp.post(new ApplicationLifecycle())
+ .api(new XxxApi())
+ .tag("abc")
+ .request(new HttpCallback>(this) {
+
+ @Override
+ public void onSucceed(HttpData result) {
+
+ }
+ });
+```
+
+* 但是你需要注意,传入 ApplicationLifecycle 将意味着框架无法自动把控请求的生命周期
+
+* 如果你采用了这样的写法,那么为了避免内存泄漏或者崩溃的事情发生
+
+* 需要你在请求的时候设置对应的 Tag,然后在恰当的时机手动取消请求(一般都在销毁或者退出的时候取消请求)
+
+#### 如何取消已发起的请求?
+
+```java
+// 取消和这个 LifecycleOwner 关联的请求
+EasyHttp.cancel(LifecycleOwner lifecycleOwner);
+// 取消指定 Tag 标记的请求
+EasyHttp.cancel(Object tag);
+// 取消所有请求
+EasyHttp.cancel();
```
\ No newline at end of file
diff --git a/README.md b/README.md
index aff36ab..68a5348 100644
--- a/README.md
+++ b/README.md
@@ -8,225 +8,71 @@
#### Gradle 集成
- android {
- // 支持 JDK 1.8
- compileOptions {
- targetCompatibility JavaVersion.VERSION_1_8
- sourceCompatibility JavaVersion.VERSION_1_8
- }
- }
-
- dependencies {
- implementation 'com.hjq:http:8.2'
- implementation 'com.squareup.okhttp3:okhttp:3.12.10'
- implementation 'com.google.code.gson:gson:2.8.5'
+```groovy
+android {
+ // 支持 JDK 1.8
+ compileOptions {
+ targetCompatibility JavaVersion.VERSION_1_8
+ sourceCompatibility JavaVersion.VERSION_1_8
}
+}
+
+dependencies {
+ implementation 'com.hjq:http:8.6'
+ implementation 'com.squareup.okhttp3:okhttp:3.12.12'
+ implementation 'com.google.code.gson:gson:2.8.5'
+}
+```
+
+#### 具体用法[请点击这里查看](HelpDoc.md)
+
+#### 不同网络请求框架之间的对比
-#### 配置权限
-
-
-
-
-
-
-
-
-#### 服务器配置
-
- public class RequestServer implements IRequestServer {
-
- @Override
- public String getHost() {
- return "https://www.baidu.com/";
- }
-
- @Override
- public String getPath() {
- return "api/";
- }
-
- @Override
- public BodyType getType() {
- // 参数以 Json 格式提交(默认是表单)
- return BodyType.JSON;
- }
- }
-
-#### 初始化
-
-> 需要配置请求结果处理,具体封装可以参考 [RequestHandler](https://github.com/getActivity/EasyHttp/blob/master/app/src/main/java/com/hjq/http/demo/http/model/RequestHandler.java)
-
- EasyConfig.with(new OkHttpClient())
- // 是否打印日志
- .setLogEnabled(BuildConfig.DEBUG)
- // 设置服务器配置
- .setServer(server)
- // 设置请求处理策略
- .setHandler(new RequestHandler())
- // 设置请求重试次数
- .setRetryCount(3)
- // 添加全局请求参数
- //.addParam("token", "6666666")
- // 添加全局请求头
- //.addHeader("time", "20191030")
- // 启用配置
- .into();
-
-> 上述是创建配置,更新配置可以使用
-
- EasyConfig.getInstance()
- .addParam("token", data.getData().getToken());
-
-#### 配置接口
-
- public final class LoginApi implements IRequestApi {
-
- @Override
- public String getApi() {
- return "user/login";
- }
-
- /** 用户名 */
- private String userName;
-
- /** 登录密码 */
- private String password;
-
- public LoginApi setUserName(String userName) {
- this.userName = userName;
- return this;
- }
-
- public LoginApi setPassword(String password) {
- this.password = password;
- return this;
- }
- }
-
-* 可为这个类的字段加上一些注解
-
- * @HttpHeader:标记这个字段是一个请求头参数
-
- * @HttpIgnore:标记这个字段不会被发送给后台
-
- * @HttpRename:重新定义这个字段发送给后台的参数名称
-
-* 可在这个类实现一些接口
-
- * implements IRequestHost:实现这个接口之后可以重新指定这个请求的主机地址
-
- * implements IRequestPath:实现这个接口之后可以重新指定这个请求的接口路径
-
- * implements IRequestType:实现这个接口之后可以重新指定这个请求的提交方式
-
-* 具体用法可以[点击这里查看](HelpDoc.md)
-
-#### 发起请求
-
-> 需要配置请求状态及生命周期处理,具体封装可以参考 [BaseActivity](https://github.com/getActivity/EasyHttp/blob/master/app/src/main/java/com/hjq/http/demo/BaseActivity.java)
-
- EasyHttp.post(this)
- .api(new LoginApi()
- .setUserName("Android 轮子哥")
- .setPassword("123456"))
- .request(new HttpCallback>(activity) {
-
- @Override
- public void onSucceed(HttpData data) {
- ToastUtils.show("登录成功");
- }
- });
-
-#### 下载文件
-
-> 下载缓存策略:在指定下载文件 md5 或者后台有返回 md5 的情况下,下载框架默认开启下载缓存模式,如果这个文件已经存在手机中,并且经过 md5 校验文件完整,框架就不会重复下载,而是直接回调下载监听。减轻服务器压力,减少用户等待时间。
-
- EasyHttp.download(this)
- .method(HttpMethod.GET)
- .file(new File(Environment.getExternalStorageDirectory(), "微信.apk"))
- .url("http://dldir1.qq.com/weixin/android/weixin708android1540.apk")
- .md5("2E8BDD7686474A7BC4A51ADC3667CABF")
- .listener(new OnDownloadListener() {
-
- @Override
- public void onStart(Call call) {
- mProgressBar.setVisibility(View.VISIBLE);
- ToastUtils.show("下载开始");
- }
-
- @Override
- public void onProgress(DownloadInfo info) {
- mProgressBar.setProgress(info.getDownloadProgress());
- }
-
- @Override
- public void onComplete(DownloadInfo info) {
- ToastUtils.show("下载完成:" + info.getFile().getPath());
- installApk(MainActivity.this, info.getFile());
- }
-
- @Override
- public void onError(DownloadInfo info, Exception e) {
- ToastUtils.show("下载出错:" + e.getMessage());
- }
-
- @Override
- public void onEnd(Call call) {
- mProgressBar.setVisibility(View.GONE);
- ToastUtils.show("下载结束");
- }
-
- }).start();
+| 功能 | [EasyHttp](https://github.com/getActivity/EasyHttp) | [Retrofit](https://github.com/square/retrofit) | [OkGo](https://github.com/jeasonlzy/okhttp-OkGo) |
+| :----: | :------: | :-----: | :-----: |
+| 动态 Host | 支持 | 不支持 | 支持 |
+| 全局参数 | 支持 | 不支持 | 支持 |
+| 超时重试 | 支持 | 不支持 | 支持 |
+| 极速下载 | 支持 | 不支持 | 不支持 |
+| 下载校验 | 支持 | 不支持 | 不支持 |
+| 注解数量 | 3 个 | 25 个 | 0 个 |
+| 上传文件类型 | File / InputStream | RequestBody | File |
+| 批量上传文件 | 支持 | 不支持 | 支持 |
+| 上传进度监听 | 支持 | 不支持 | 支持 |
+| Json 参数提交 | 支持 | 支持 | 支持 |
+| 请求生命周期 | 自动管控 | 需要封装 | 需要封装 |
+| 参数传值方式 | 字段名 + 字段值 | 方法参数名 + 方法参数值 | 定义 key 和 value |
+| 参数灵活性 | 不强制传入 | 强制全部传入 | 不强制传入 |
+| 框架维护状态 | 维护中 | 维护中 | 停止维护 |
-#### 关于 Http 明文请求
-
-> Android P 限制了明文流量的网络请求,非加密的流量请求都会被系统禁止掉。
-如果当前应用的请求是 http 请求,而非 https ,这样就会导系统禁止当前应用进行该请求,如果 WebView 的 url 用 http 协议,同样会出现加载失败,https 不受影响
-
-> 在 res 下新建一个 xml 目录,然后创建一个名为:network_security_config.xml 文件 ,该文件内容如下
+* Retrofit 在我看来并不是那么好用,因为很多常用的功能实现起来比较麻烦,动态 Host 要写拦截器,日志打印要写拦截器,就连最常用的添加全局参数也要写拦截器,一个拦截器意味着要写很多代码,如果写得不够严谨还有可能出现 Bug,从而影响整个 OkHttp 请求流程,我经常在想这些功能能不能都用一句代码搞定,因为我觉得这些功能是框架设计的时候应该考虑的,这便是我做这个框架的初心。
-
-
-
-
+* 本框架采用了 OOP 思想,一个请求代表一个对象,通过类的继承和实现的特性来实现接口的动态化,几乎涵盖接口开发中所有的功能,使用起来非常简单灵活。
-> 然后在 AndroidManifest.xml application 标签内应用上面的xml配置
+* 有很多人觉得写一个接口类很麻烦,这个点确实有点麻烦,但是这块的付出是有收获的,从前期开发的效率考虑:OkGo > EasyHttp > Retrofit,但是从后期维护的效率考虑:EasyHttp > Retrofit > OkGo,之所以比较这三个框架,是因为框架的设计思想不同,但是我始终认为 EasyHttp 才是最好的设计,所以我创造了它。
-
+* 前期开发和后期维护哪个更重要?我觉得都重要,但是如果两者之间有利益冲突,我会毫不犹豫选择后期维护,因为前期开发占据的是小头,后期的持续维护才是大头。
#### 混淆规则
-
- # OkHttp3
- -keepattributes Signature
- -keepattributes *Annotation*
- -keep class okhttp3.** { *; }
- -keep interface okhttp3.** { *; }
- -dontwarn okhttp3.**
- -dontwarn okio.**
-
- # 不混淆这个包下的字段名
- -keepclassmembernames class com.hjq.http.demo.http.** {
- ;
- }
-
-#### 对比 Retrofit
-
-| 功能 | Retrofit 框架 | EasyHttp 框架 |
-| :----: | :------: | :-----: |
-| 动态 Host | 不支持 | 支持 |
-| 全局参数 | 不支持 | 支持 |
-| 动态参数 | 不支持 | 支持 |
-| 超时重试 | 不支持 | 支持 |
-| 极速下载 | 不支持 | 支持 |
-| 下载校验 | 不支持 | 支持 |
-| 注解数量 | 25 个 | 3 个 |
-| 上传文件 | RequestBody | File / InputStream |
-| 生命周期 | 需要封装 | 自动管控 |
+
+```groovy
+# OkHttp3
+-keepattributes Signature
+-keepattributes *Annotation*
+-keep class okhttp3.** { *; }
+-keep interface okhttp3.** { *; }
+-dontwarn okhttp3.**
+-dontwarn okio.**
+
+# 不混淆这个包下的字段名
+-keepclassmembernames class com.hjq.http.demo.http.** {
+ ;
+}
+```
#### 作者的其他开源项目
-* 架构工程:[AndroidProject](https://github.com/getActivity/AndroidProject)
+* 安卓架构:[AndroidProject](https://github.com/getActivity/AndroidProject)
* 日志框架:[Logcat](https://github.com/getActivity/Logcat)
@@ -240,12 +86,6 @@
* 悬浮窗框架:[XToast](https://github.com/getActivity/XToast)
-#### 特别感谢
-
-[张鸿洋](https://github.com/hongyangAndroid)
-
-[WanAndroid](https://www.wanandroid.com/)
-
#### Android技术讨论Q群:78797078
#### 如果您觉得我的开源库帮你节省了大量的开发时间,请扫描下方的二维码随意打赏,要是能打赏个 10.24 :monkey_face:就太:thumbsup:了。您的支持将鼓励我继续创作:octocat:
@@ -254,6 +94,12 @@
#### [点击查看捐赠列表](https://github.com/getActivity/Donate)
+#### 特别感谢
+
+[张鸿洋](https://github.com/hongyangAndroid)
+
+[WanAndroid](https://www.wanandroid.com/)
+
## License
```text
diff --git a/app/build.gradle b/app/build.gradle
index 6208f60..c1058c2 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,7 +1,11 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 28
+ compileSdkVersion 30
+
+ lintOptions {
+ abortOnError false
+ }
// 支持 JDK 1.8
compileOptions {
@@ -12,9 +16,9 @@ android {
defaultConfig {
applicationId "com.hjq.http.demo"
minSdkVersion 14
- targetSdkVersion 28
- versionCode 82
- versionName "8.2"
+ targetSdkVersion 30
+ versionCode 86
+ versionName "8.6"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -24,35 +28,37 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
release {
- minifyEnabled true
+ minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
+ // 依赖 libs 目录下所有的 jar 和 aar 包
implementation fileTree(include: ['*.jar'], dir: 'libs')
+ implementation fileTree(include: ['*.aar'], dir: 'libs')
+
implementation project(':library')
testImplementation 'junit:junit:4.13'
- androidTestImplementation 'androidx.test.ext:junit:1.1.1'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
-
+ androidTestImplementation 'androidx.test.ext:junit:1.1.2'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
- implementation 'androidx.appcompat:appcompat:1.1.0'
- implementation 'com.google.android.material:material:1.1.0'
+ // 谷歌兼容库:https://developer.android.google.cn/jetpack/androidx/releases/appcompat?hl=zh-cn
+ implementation 'androidx.appcompat:appcompat:1.3.0-alpha02'
// 标题栏:https://github.com/getActivity/TitleBar
- implementation 'com.hjq:titlebar:6.5'
+ implementation 'com.hjq:titlebar:8.0'
// 吐司工具类:https://github.com/getActivity/ToastUtils
- implementation 'com.hjq:toast:8.6'
+ implementation 'com.hjq:toast:8.8'
// 权限请求框架:https://github.com/getActivity/XXPermissions
- implementation 'com.hjq:xxpermissions:6.5'
+ implementation 'com.hjq:xxpermissions:8.8'
// 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
- implementation 'com.squareup.okhttp3:okhttp:3.12.10'
+ implementation 'com.squareup.okhttp3:okhttp:3.12.12'
// 日志调试:https://github.com/getActivity/Logcat
- debugImplementation 'com.hjq:logcat:8.2'
+ debugImplementation 'com.hjq:logcat:8.6'
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3ee8451..a4991a7 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -10,6 +10,7 @@
+
@@ -23,6 +24,7 @@
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:theme="@style/AppTheme"
+ tools:ignore="LockedOrientationActivity"
tools:targetApi="n">
diff --git a/app/src/main/java/com/hjq/http/demo/MainActivity.java b/app/src/main/java/com/hjq/http/demo/MainActivity.java
index 10de53e..2f748b4 100644
--- a/app/src/main/java/com/hjq/http/demo/MainActivity.java
+++ b/app/src/main/java/com/hjq/http/demo/MainActivity.java
@@ -16,7 +16,6 @@
import androidx.core.content.FileProvider;
import com.hjq.http.EasyHttp;
-import com.hjq.http.EasyLog;
import com.hjq.http.demo.http.model.HttpData;
import com.hjq.http.demo.http.request.SearchAuthorApi;
import com.hjq.http.demo.http.request.SearchBlogsApi;
@@ -24,7 +23,8 @@
import com.hjq.http.demo.http.response.SearchBean;
import com.hjq.http.listener.HttpCallback;
import com.hjq.http.listener.OnDownloadListener;
-import com.hjq.http.model.DownloadInfo;
+import com.hjq.http.listener.OnUpdateListener;
+import com.hjq.http.model.DataClass;
import com.hjq.http.model.HttpMethod;
import com.hjq.permissions.OnPermission;
import com.hjq.permissions.Permission;
@@ -57,6 +57,7 @@ protected void onCreate(Bundle savedInstanceState) {
findViewById(R.id.btn_main_get).setOnClickListener(this);
findViewById(R.id.btn_main_post).setOnClickListener(this);
+ findViewById(R.id.btn_main_exec).setOnClickListener(this);
findViewById(R.id.btn_main_update).setOnClickListener(this);
findViewById(R.id.btn_main_download).setOnClickListener(this);
requestPermission();
@@ -64,7 +65,7 @@ protected void onCreate(Bundle savedInstanceState) {
private void requestPermission() {
XXPermissions.with(this)
- .permission(Permission.Group.STORAGE)
+ .permission(Permission.MANAGE_EXTERNAL_STORAGE)
.request(this);
}
@@ -78,10 +79,10 @@ public void hasPermission(List granted, boolean all) {
}
@Override
- public void noPermission(List denied, boolean quick) {
- if (quick) {
+ public void noPermission(List denied, boolean never) {
+ if (never) {
ToastUtils.show("授权失败,请手动授予权限");
- XXPermissions.startPermissionActivity(this, true);
+ XXPermissions.startPermissionActivity(this, denied);
} else {
ToastUtils.show("请先授予权限");
requestPermission();
@@ -91,7 +92,7 @@ public void noPermission(List denied, boolean quick) {
@Override
protected void onRestart() {
super.onRestart();
- if (XXPermissions.hasPermission(this, Permission.Group.STORAGE)) {
+ if (XXPermissions.hasPermission(this, Permission.MANAGE_EXTERNAL_STORAGE)) {
hasPermission(null, true);
} else {
requestPermission();
@@ -109,7 +110,7 @@ public void onClick(View v) {
@Override
public void onSucceed(HttpData result) {
- ToastUtils.show("请求成功,请看日志");
+ ToastUtils.show("Get 请求成功,请看日志");
}
});
break;
@@ -121,26 +122,73 @@ public void onSucceed(HttpData result) {
@Override
public void onSucceed(HttpData result) {
- ToastUtils.show("请求成功,请看日志");
+ ToastUtils.show("Post 请求成功,请看日志");
}
});
break;
+ case R.id.btn_main_exec:
+ // 在主线程中不能做耗时操作
+ new Thread(() -> {
+ runOnUiThread(this::showDialog);
+ try {
+ HttpData data = EasyHttp.post(MainActivity.this)
+ .api(new SearchBlogsApi()
+ .setKeyword("搬砖不再有"))
+ .execute(new DataClass>() {});
+ ToastUtils.show("同步请求成功,请看日志");
+ } catch (Exception e) {
+ e.printStackTrace();
+ ToastUtils.show(e.getMessage());
+ }
+ runOnUiThread(this::hideDialog);
+ }).start();
+ break;
case R.id.btn_main_update:
+ if (mProgressBar.getVisibility() == View.VISIBLE) {
+ ToastUtils.show("当前正在上传或者下载,请等待完成之后再进行操作");
+ return;
+ }
+
File file = new File(Environment.getExternalStorageDirectory(), getString(R.string.app_name) + ".png");
// 生成图片到本地
- drawableToFile(ContextCompat.getDrawable(this, R.mipmap.ic_launcher), file);
+ drawableToFile(ContextCompat.getDrawable(this, R.drawable.bg_material), file);
EasyHttp.post(this)
.api(new UpdateImageApi(file))
- .request(new HttpCallback(this) {
+ .request(new OnUpdateListener() {
+
+ @Override
+ public void onStart(Call call) {
+ mProgressBar.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void onUpdate(long totalByte, long updateByte, int progress) {
+ mProgressBar.setProgress(progress);
+ }
@Override
- public void onSucceed(String result) {
+
+ public void onSucceed(Void result) {
ToastUtils.show("上传成功");
}
+
+ @Override
+ public void onFail(Exception e) {
+ ToastUtils.show("上传失败");
+ }
+
+ @Override
+ public void onEnd(Call call) {
+ mProgressBar.setVisibility(View.GONE);
+ }
});
break;
case R.id.btn_main_download:
+ if (mProgressBar.getVisibility() == View.VISIBLE) {
+ ToastUtils.show("当前正在上传或者下载,请等待完成之后再进行操作");
+ return;
+ }
EasyHttp.download(this)
.method(HttpMethod.GET)
.file(new File(Environment.getExternalStorageDirectory(), "微信.apk"))
@@ -150,31 +198,29 @@ public void onSucceed(String result) {
.listener(new OnDownloadListener() {
@Override
- public void onStart(Call call) {
+ public void onStart(File file) {
mProgressBar.setVisibility(View.VISIBLE);
- ToastUtils.show("下载开始");
}
@Override
- public void onProgress(DownloadInfo info) {
- mProgressBar.setProgress(info.getDownloadProgress());
+ public void onProgress(File file, long totalByte, long downloadByte, int progress) {
+ mProgressBar.setProgress(progress);
}
@Override
- public void onComplete(DownloadInfo info) {
- ToastUtils.show("下载完成:" + info.getFile().getPath());
- installApk(MainActivity.this, info.getFile());
+ public void onComplete(File file) {
+ ToastUtils.show("下载完成:" + file.getPath());
+ installApk(MainActivity.this, file);
}
@Override
- public void onError(DownloadInfo info, Exception e) {
+ public void onError(File file, Exception e) {
ToastUtils.show("下载出错:" + e.getMessage());
}
@Override
- public void onEnd(Call call) {
+ public void onEnd(File file) {
mProgressBar.setVisibility(View.GONE);
- ToastUtils.show("下载结束");
}
}).start();
@@ -193,8 +239,8 @@ private void installApk(final Context context, final File file) {
.permission(Permission.REQUEST_INSTALL_PACKAGES)
.request(new OnPermission() {
@Override
- public void hasPermission(List granted, boolean isAll) {
- if (isAll) {
+ public void hasPermission(List granted, boolean all) {
+ if (all) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri uri;
@@ -240,7 +286,7 @@ private void drawableToFile(Drawable drawable, File file) {
((BitmapDrawable) drawable).getBitmap().compress(Bitmap.CompressFormat.PNG, 100, out);
out.close();
} catch (IOException e) {
- EasyLog.print(e);
+ e.printStackTrace();
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/hjq/http/demo/MyApplication.java b/app/src/main/java/com/hjq/http/demo/MyApplication.java
index 3474fe7..b6322f4 100644
--- a/app/src/main/java/com/hjq/http/demo/MyApplication.java
+++ b/app/src/main/java/com/hjq/http/demo/MyApplication.java
@@ -29,7 +29,10 @@ public void onCreate() {
server = new ReleaseServer();
}
- EasyConfig.with(new OkHttpClient())
+ OkHttpClient okHttpClient = new OkHttpClient.Builder()
+ .build();
+
+ EasyConfig.with(okHttpClient)
// 是否打印日志
//.setLogEnabled(BuildConfig.DEBUG)
// 设置服务器配置
@@ -45,6 +48,8 @@ public void intercept(String url, String tag, HttpParams params, HttpHeaders hea
})
// 设置请求重试次数
.setRetryCount(1)
+ // 设置请求重试时间
+ .setRetryTime(1000)
// 添加全局请求参数
//.addParam("token", "6666666")
// 添加全局请求头
diff --git a/app/src/main/java/com/hjq/http/demo/http/model/HttpListData.java b/app/src/main/java/com/hjq/http/demo/http/model/HttpListData.java
new file mode 100644
index 0000000..ce66bfa
--- /dev/null
+++ b/app/src/main/java/com/hjq/http/demo/http/model/HttpListData.java
@@ -0,0 +1,47 @@
+package com.hjq.http.demo.http.model;
+
+import java.util.List;
+
+/**
+ * author : Android 轮子哥
+ * github : https://github.com/getActivity/EasyHttp
+ * time : 2020/10/07
+ * desc : 统一接口列表数据结构
+ */
+public class HttpListData extends HttpData> {
+
+ public static class ListBean {
+
+ /** 当前页码 */
+ private int pageIndex;
+ /** 页大小 */
+ private int pageSize;
+ /** 总数量 */
+ private int totalNumber;
+ /** 数据 */
+ private List items;
+
+ /**
+ * 判断是否是最后一页
+ */
+ public boolean isLastPage() {
+ return Math.ceil((float) totalNumber / pageSize) <= pageIndex;
+ }
+
+ public int getTotalNumber() {
+ return totalNumber;
+ }
+
+ public int getPageIndex() {
+ return pageIndex;
+ }
+
+ public int getPageSize() {
+ return pageSize;
+ }
+
+ public List getItems() {
+ return items;
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/hjq/http/demo/http/model/RequestHandler.java b/app/src/main/java/com/hjq/http/demo/http/model/RequestHandler.java
index 3dc1f63..90d9ab2 100644
--- a/app/src/main/java/com/hjq/http/demo/http/model/RequestHandler.java
+++ b/app/src/main/java/com/hjq/http/demo/http/model/RequestHandler.java
@@ -2,8 +2,6 @@
import android.app.Application;
import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
@@ -38,11 +36,13 @@
import org.json.JSONObject;
import java.io.IOException;
+import java.io.InputStream;
import java.lang.reflect.Type;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.List;
+import okhttp3.Headers;
import okhttp3.Response;
import okhttp3.ResponseBody;
@@ -74,14 +74,17 @@ public Object requestSucceed(LifecycleOwner lifecycle, Response response, Type t
throw new ResponseException(mApplication.getString(R.string.http_response_error) + ",responseCode:" + response.code() + ",message:" + response.message(), response);
}
+ if (Headers.class.equals(type)) {
+ return response.headers();
+ }
+
ResponseBody body = response.body();
if (body == null) {
return null;
}
- if (Bitmap.class.equals(type)) {
- // 如果这是一个 Bitmap 对象
- return BitmapFactory.decodeStream(body.byteStream());
+ if (InputStream.class.equals(type)) {
+ return body.byteStream();
}
String text;
diff --git a/app/src/main/java/com/hjq/http/demo/http/request/UpdateImageApi.java b/app/src/main/java/com/hjq/http/demo/http/request/UpdateImageApi.java
index ea21fa3..2e09357 100644
--- a/app/src/main/java/com/hjq/http/demo/http/request/UpdateImageApi.java
+++ b/app/src/main/java/com/hjq/http/demo/http/request/UpdateImageApi.java
@@ -1,9 +1,11 @@
package com.hjq.http.demo.http.request;
import com.hjq.http.config.IRequestApi;
-import com.hjq.http.config.IRequestHost;
+import com.hjq.http.config.IRequestServer;
import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
/**
* author : Android 轮子哥
@@ -11,7 +13,7 @@
* time : 2019/12/14
* desc : 上传图片
*/
-public final class UpdateImageApi implements IRequestHost, IRequestApi {
+public final class UpdateImageApi implements IRequestServer, IRequestApi {
@Override
public String getHost() {
@@ -26,12 +28,15 @@ public String getApi() {
/** 本地图片 */
private File image;
+ private List files = new ArrayList<>();
+
public UpdateImageApi(File image) {
this.image = image;
}
public UpdateImageApi setImage(File image) {
this.image = image;
+ files.add(image);
return this;
}
}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_material.jpg b/app/src/main/res/drawable/bg_material.jpg
new file mode 100644
index 0000000..b0a3f67
Binary files /dev/null and b/app/src/main/res/drawable/bg_material.jpg differ
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 378754c..06f772b 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -34,14 +34,21 @@
android:id="@+id/btn_main_get"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Get请求" />
+ android:text="Get 请求" />
+ android:text="Post 请求" />
+
+