Skip to content

Commit

Permalink
修复上传 FileContentResolver 对象无法识别的问题
Browse files Browse the repository at this point in the history
新增支持传入 FileContentResolver 文件名称参数
新增支持获取 FileContentResolver 的文件大小
修改 IRequestHandler.requestStart 方法参数类型
修改 FileWrapper 打开输入流和输出流的方法命名
  • Loading branch information
getActivity committed Sep 21, 2021
1 parent d6faf05 commit 4db8dec
Show file tree
Hide file tree
Showing 16 changed files with 315 additions and 121 deletions.
Binary file modified EasyHttp.apk
Binary file not shown.
138 changes: 90 additions & 48 deletions HelpDoc.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@

* [请求缓存](#请求缓存)

* [分区存储适配](#分区存储适配)

* [疑难解答](#疑难解答)

* [如何添加全局参数](#如何添加全局参数)
Expand Down Expand Up @@ -76,14 +78,14 @@

* [我想取消请求时显示的加载对话框该怎么办](#我想取消请求时显示的加载对话框该怎么办)

* [如何在 ViewModel 中使用 EasyHttp 请求网络](如何在-viewmodel-中使用-easyhttp-请求网络)

* [搭配 RxJava](#搭配-rxjava)

* [准备工作](#准备工作)

* [多个请求串行](#多个请求串行)

* [多个请求并行](#多个请求并行)

* [发起轮询请求](#发起轮询请求)

* [对返回的数据进行包装](#对返回的数据进行包装)
Expand Down Expand Up @@ -230,7 +232,7 @@ public final class LoginApi implements IRequestApi {

* @HttpIgnore:标记这个字段不会被发送给后台

* @HttpRename重新定义这个字段发送给后台的参数名称
* @HttpRename重新定义这个字段发送给后台的参数或者请求头名称

* 可在这个类实现一些接口

Expand Down Expand Up @@ -544,6 +546,37 @@ public class XxxServer implements IRequestServer {
}
```

#### 分区存储适配

* 在 Android 10 之前,我们在读写外部存储的时候,可以直接使用 File 对象来上传或者下载文件,但是在 Android 10 之后,如果你的项目需要 Android 10 分区存储的特性,那么在读写外部存储文件的时候,就不能直接使用 File 对象,因为 `ContentResolver.insert` 返回是一个 `Uri` 对象,这个时候就需要使用到 `FileContentResolver` 对象了(这个对象是 File 的子类),具体使用案例如下:

```java
File outputFile;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ContentValues values = new ContentValues();
.........
// 生成一个新的 uri 路径
Uri outputUri = getContentResolver().insert(MediaStore.Xxx.Media.EXTERNAL_CONTENT_URI, values);
// 适配 Android 10 分区存储特性
outputFile = new FileContentResolver(context, outputUri);
} else {
outputFile = new File(xxxx);
}

EasyHttp.post(this)
.api(new XxxApi()
.setImage(outputFile))
.request(new HttpCallback<Xxx <Xxx>>(this) {

@Override
public void onSucceed(Xxx<Xxx> data) {

}
});
```

* 这是上传的案例,下载也同理,这里不再赘述。

# 疑难解答

#### 如何添加全局参数
Expand Down Expand Up @@ -1224,6 +1257,58 @@ EasyHttp.post(this)
});
```

#### 如何在 ViewModel 中使用 EasyHttp 请求网络

* 第一步:封装一个 BaseViewModel,并将 LifecycleOwner 特性植入进去

```java
public class BaseViewModel extends ViewModel implements LifecycleOwner {

private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);

public BaseViewModel() {
mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
}

@Override
protected void onCleared() {
super.onCleared();
mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
}

@NonNull
@Override
public Lifecycle getLifecycle() {
return mLifecycle;
}
}
```

* 第二步:让业务 ViewModel 类继承至 BaseViewModel,具体案例如下

```java
public class XxxViewModel extends BaseViewModel {

public void xxxx() {
EasyHttp.post(this)
.api(new XxxApi())
.request(new OnHttpListener<HttpData<Xxx>>() {

@Override
public void onSucceed(HttpData<Xxx> result) {

}

@Override
public void onFail(Exception e) {

}
});
}
}
```

# 搭配 RxJava

#### 准备工作
Expand Down Expand Up @@ -1288,53 +1373,10 @@ Observable.create(new ObservableOnSubscribe<HttpData<SearchBean>>() {
});
```

#### 多个请求并行

```java
Observable.create(new ObservableOnSubscribe<IRequestApi>() {

@Override
public void subscribe(ObservableEmitter<IRequestApi> emitter) throws Exception {
SearchBlogsApi api1 = new SearchBlogsApi()
.setKeyword("1");
SearchBlogsApi api2 = new SearchBlogsApi()
.setKeyword("2");

emitter.onNext(api1);
emitter.onNext(api2);
emitter.onComplete();
}
})
.map(new Function<IRequestApi, HttpData<Void>>() {

@Override
public HttpData<Void> apply(IRequestApi api) throws Exception {
try {
return EasyHttp.post(MainActivity.this)
.api(api)
.execute(new ResponseClass<HttpData<Void>>() {});
} catch (Exception e) {
e.printStackTrace();
ToastUtils.show(e.getMessage());
throw e;
}
}
})
// 让被观察者执行在 IO 线程
.subscribeOn(Schedulers.io())
// 让观察者执行在主线程
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<HttpData<Void>>() {

@Override
public void accept(HttpData<Void> data) throws Exception {
Log.d("EasyHttp", "最终结果为:" + data.getMessage());
}
});
```

#### 发起轮询请求

* 如果轮询的次数是有限,可以考虑使用 Http 请求来实现,但是如果轮询的次数是无限的,那么不推荐使用 Http 请求来实现,应当使用 WebSocket 来做,又或者其他长链接协议来做。

```java
// 发起轮询请求,共发起三次请求,第一次请求在 5 秒后触发,剩下两次在 1 秒 和 2 秒后触发
Observable.intervalRange(1, 3, 5000, 1000, TimeUnit.MILLISECONDS)
Expand Down
43 changes: 37 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ android {
dependencies {
// 网络请求框架:https://github.com/getActivity/EasyHttp
implementation 'com.github.getActivity:EasyHttp:10.0'
implementation 'com.github.getActivity:EasyHttp:10.2'
// OkHttp 框架:https://github.com/square/okhttp
// noinspection GradleDependency
implementation 'com.squareup.okhttp3:okhttp:3.12.13'
Expand All @@ -65,9 +65,9 @@ dependencies {

| 功能或细节 | [EasyHttp](https://github.com/getActivity/EasyHttp) | [Retrofit](https://github.com/square/retrofit) | [OkGo](https://github.com/jeasonlzy/okhttp-OkGo) |
| :----: | :------: | :-----: | :-----: |
| 对应版本 | 10.0 | 2.9.0 | 3.0.4 |
| 对应版本 | 10.2 | 2.9.0 | 3.0.4 |
| issues 数 | [![](https://img.shields.io/github/issues/getActivity/EasyHttp.svg)](https://github.com/getActivity/EasyHttp/issues) | [![](https://img.shields.io/github/issues/square/retrofit.svg)](https://github.com/square/retrofit/issues) | [![](https://img.shields.io/github/issues/jeasonlzy/okhttp-OkGo.svg)](https://github.com/jeasonlzy/okhttp-OkGo/issues) |
| **aar 包大小** | 74 KB | 123 KB | 131 KB |
| **aar 包大小** | 76 KB | 123 KB | 131 KB |
| minSdk 要求 | API 14+ | API 21+ | API 14+ |
| 配置多域名 ||||
| **动态 Host** ||||
Expand All @@ -82,7 +82,8 @@ dependencies {
| Json 参数提交 ||||
| **请求代码定位** ||||
| **延迟发起请求** ||||
| 上传文件类型 | File / InputStream / RequestBody | RequestBody | File |
| **分区存储适配** ||||
| 上传文件类型 | File / FileContentResolver <br> InputStream / RequestBody | RequestBody | File |
| **请求生命周期** | 自动管控 | 需要封装 | 需要封装 |
| 参数传值方式 | 字段名 + 字段值 | 参数名 + 参数值 | 定义 Key + Value |
| 框架灵活性 ||||
Expand All @@ -105,9 +106,39 @@ dependencies {

* EasyHttp 采用了 OOP 思想,一个请求代表一个对象,通过类继承和实现的特性来对接口进行动态化配置,几乎涵盖接口开发中所有的功能,使用起来非常简单灵活。而 Retrofit 采用的是注解方式,缺点是灵活性极低,因为注解上面只能放常量,也就会限定你在注解上面的一切参数只能是事先定义好的,这对接口的动态化配置极不利的。

* 有很多人觉得写一个接口类很麻烦,这个点确实有点麻烦,但是这块的付出是有收获的,从前期开发的效率考虑:OkGo > EasyHttp > Retrofit,但是从后期维护的效率考虑:EasyHttp > Retrofit > OkGo,之所以比较这三个框架,是因为框架的设计思想不同,但是我始终认为 EasyHttp 才是最好的设计,所以我创造了它。
* 有很多人觉得写一个接口类很麻烦,关于这个问题我后面已经想到一个好方案了,大家可以将 Api 类和 Bean 类写在一起,这样大家就不需要多写一个类了,具体写法示例如下:

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

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

private int xxx;

public XxxApi setXxx(int xxx) {
this.xxx = xxx;
return this;
}

......

public final static class Bean {

private int xyz;

public int getXyz() {
return xyz;
}

......
}
}
```

* 是不是很机智?这样不仅很好地解决了这一问题,还能将一个接口所有的信息都包裹在这个类中,非常直观,一览如云,妥妥的一箭双雕。

#### 生命周期自动管控介绍

Expand Down
17 changes: 10 additions & 7 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ android {
applicationId 'com.hjq.easy.demo'
minSdkVersion 16
targetSdkVersion 30
versionCode 1000
versionName '10.0'
versionCode 1020
versionName '10.2'
}

// 支持 JDK 1.8
Expand Down Expand Up @@ -60,8 +60,8 @@ dependencies {

implementation project(':library')

// AppCompat 库:https://developer.android.google.cn/jetpack/androidx/releases/appcompat?hl=zh-cn
implementation 'androidx.appcompat:appcompat:1.3.0'
// AndroidX 库:https://github.com/androidx/androidx
implementation 'androidx.appcompat:appcompat:1.3.1'

// OkHttp 框架:https://github.com/square/okhttp
// 升级注意事项:https://www.jianshu.com/p/d12d0f536f55
Expand All @@ -72,19 +72,22 @@ dependencies {
implementation 'com.github.getActivity:ToastUtils:9.5'

// 权限请求框架:https://github.com/getActivity/XXPermissions
implementation 'com.github.getActivity:XXPermissions:12.0'
implementation 'com.github.getActivity:XXPermissions:12.3'

// 标题栏框架:https://github.com/getActivity/TitleBar
implementation 'com.github.getActivity:TitleBar:8.6'
implementation 'com.github.getActivity:TitleBar:9.2'

// Json 解析框架:https://github.com/google/gson
implementation 'com.google.code.gson:gson:2.8.8'
// Gson 解析容错:https://github.com/getActivity/GsonFactory
implementation 'com.github.getActivity:GsonFactory:5.2'

// 日志调试框架:https://github.com/getActivity/Logcat
debugImplementation 'com.github.getActivity:Logcat:9.8'
debugImplementation 'com.github.getActivity:Logcat:9.9'

// 腾讯 MMKV:https://github.com/Tencent/MMKV
implementation 'com.tencent:mmkv-static:1.2.10'

// 内存泄漏监测框架:https://github.com/square/leakcanary
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
}
2 changes: 1 addition & 1 deletion app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<com.hjq.bar.TitleBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:backButton="false"
app:leftIcon="@null"
app:title="https://github.com/getActivity/EasyHttp" />

<ProgressBar
Expand Down
4 changes: 2 additions & 2 deletions library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ android {

defaultConfig {
minSdkVersion 14
versionCode 1000
versionName "10.0"
versionCode 1020
versionName "10.2"
}

// 使用 JDK 1.8
Expand Down
Loading

0 comments on commit 4db8dec

Please sign in to comment.