经过前面的封装,我的网络请求库已经使用了很长一段时间了,但还是觉得写的代码多了点,而且还不支持缓存的问题.
今天我将继续分享我的后续优化和缓存的解决方案.
优化
为了让在Activity和Fragment中发的网络请求自动绑定生命周期,而不需要每次都重复的写同一行代码,我修改了原来RxUtil
类,下面我附上目前这个类的完整代码.
public class RxUtil {
public static <T> LifecycleTransformer<T> bindToLifecycle(LifecycleProvider provider) {
if (provider instanceof RxAppCompatActivity) {
return ((RxAppCompatActivity) provider).bindToLifecycle();
} else if (provider instanceof RxFragment) {
return ((RxFragment) provider).bindToLifecycle();
} else {
throw new IllegalArgumentException("class must extents RxAppCompatActivity or RxFragment");
}
}
public static <T> LifecycleTransformer<T> bindToLifecycle(LifecycleProvider provider, ActivityEvent event) {
if (provider instanceof RxAppCompatActivity) {
return ((RxAppCompatActivity) provider).bindUntilEvent(event);
} else {
throw new IllegalArgumentException("class must extents RxAppCompatActivity");
}
}
public static <T> LifecycleTransformer<T> bindToLifecycle(LifecycleProvider provider, FragmentEvent event) {
if (provider instanceof RxFragment) {
return ((RxFragment) provider).bindUntilEvent(event);
} else {
throw new IllegalArgumentException("class must extents RxFragment");
}
}
public static <T> ObservableTransformer<T, T> applySchedulers(final LifecycleProvider provider) {
return new ObservableTransformer<T, T>() {
@Override public ObservableSource<T> apply(@NonNull Observable<T> upstream) {
return upstream
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(RxUtil.<T>bindToLifecycle(provider));
}
};
}
public static <T> ObservableTransformer<T, T> applySchedulers(final LifecycleProvider provider, final ActivityEvent event) {
return new ObservableTransformer<T, T>() {
@Override public ObservableSource<T> apply(@NonNull Observable<T> upstream) {
return upstream
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(RxUtil.<T>bindToLifecycle(provider, event));
}
};
}
public static <T> ObservableTransformer<T, T> applySchedulers(final LifecycleProvider provider, final FragmentEvent event) {
return new ObservableTransformer<T, T>() {
@Override public ObservableSource<T> apply(@NonNull Observable<T> upstream) {
return upstream
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(RxUtil.<T>bindToLifecycle(provider, event));
}
};
}
public static <T> ObservableTransformer<T, T> applySchedulers(final LifecycleProvider provider, @NonNull final Dialog dialog) {
return new ObservableTransformer<T, T>() {
@Override public ObservableSource<T> apply(@NonNull Observable<T> upstream) {
return upstream
.delay(1, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.doOnSubscribe(new Consumer<Disposable>() {
@Override
public void accept(@NonNull final Disposable disposable) throws Exception {
dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override public void onCancel(DialogInterface dialog) {
disposable.dispose();
}
});
dialog.show();
}
})
.observeOn(AndroidSchedulers.mainThread())
.doOnTerminate(new Action() {
@Override public void run() throws Exception {
dialog.dismiss();
}
})
.compose(RxUtil.<T>bindToLifecycle(provider));
}
};
}
public static <T> ObservableTransformer<T, T> applySchedulers(final LifecycleProvider provider, final ActivityEvent event, @NonNull final Dialog dialog) {
return new ObservableTransformer<T, T>() {
@Override public ObservableSource<T> apply(@NonNull Observable<T> upstream) {
return upstream
.delay(1, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.doOnSubscribe(new Consumer<Disposable>() {
@Override
public void accept(@NonNull final Disposable disposable) throws Exception {
dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override public void onCancel(DialogInterface dialog) {
disposable.dispose();
}
});
dialog.show();
}
})
.observeOn(AndroidSchedulers.mainThread())
.doOnTerminate(new Action() {
@Override public void run() throws Exception {
dialog.dismiss();
}
})
.compose(RxUtil.<T>bindToLifecycle(provider, event));
}
};
}
public static <T> ObservableTransformer<T, T> applySchedulers(final LifecycleProvider provider, final FragmentEvent event, @NonNull final Dialog dialog) {
return new ObservableTransformer<T, T>() {
@Override public ObservableSource<T> apply(@NonNull Observable<T> upstream) {
return upstream
.delay(1, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.doOnSubscribe(new Consumer<Disposable>() {
@Override
public void accept(@NonNull final Disposable disposable) throws Exception {
dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override public void onCancel(DialogInterface dialog) {
disposable.dispose();
}
});
dialog.show();
}
})
.observeOn(AndroidSchedulers.mainThread())
.doOnTerminate(new Action() {
@Override public void run() throws Exception {
dialog.dismiss();
}
})
.compose(RxUtil.<T>bindToLifecycle(provider, event));
}
};
}
}
对于这个类,我自己都觉得挺蛋疼的 ,平白无故的写了很多重复的代码.主要原因在于rxlifecycle2-android
这个包中的ActivityEvent
和FragmentEvent
是两个独立的枚举没法合并,为了保证传入的参数安全,只能重载方法了.
此外这次新增了RxLifecycle中的bindUntilEvent()的支持.
缓存
缓存这部分,因为用了RxJava很自然的就想到去用RxCache,但是后来才发现里面有好大的一个坑,而RxCache把这个锅推给了Gson.
如果我们的实体类中使用int
类型,在正常的网络请求中能正常的获得解析,但是在配置了RxCache后,就会出现返回的对象类型发生了变化,变成了LinkedTreeMap
,坑爹有木有...为啥会这样呢?
当查看了缓存的内容后,你会发现原本的int
类型变成了double
了,比如用户的年龄9
变成了9.0
,这样原来的实体类就解析不了.只有另辟捷径了----使用okhttp3
的缓存方法,Retrofit2
支持给请求添加自定义的header,引用自己项目中的一个接口:
@GET("api/car/queryCarBrand")
@Headers("Cache-Control: public, max-age=60")
Observable<Result<List<CarBrand>>> queryCarBrand();
上面的接口添加了缓存控制,在第一次网络请求被缓存后,在60秒内不会再请求服务器而是读取缓存中的数据.
为此我们需要再修改两个地方:
一. Retrofit初始化的时候
OkHttpClient.Builder okHttpBuilder = new OkHttpClient.Builder();
...
okHttpBuilder.cache(new Cache(file,size));//file是缓存路径,size缓存池大小
...
二. 请求头的修改.
一般情况下应该是服务器告诉我们是否该缓存这次的请求结果,虽然我们现在请求接口上配置了请求头,但是服务器不知道或者没有修改返回的请求头,我们拿到的返回结果请求头中依然没有Cache-Control
,这样okhttp
依然不会缓存请求结果.
我的处理方式是在修改请求头拦截器
public class HeaderInterceptor implements Interceptor {
@Override public Response intercept(Chain chain) throws IOException {
Request.Builder requestBuilder = chain.request().newBuilder();
ArrayMap<String, String> headers = BaseApp.getAppContext().getRequestHeader();
//如果公共请求头不为空,则构建新的请求
if (headers != null) {
for (String key : headers.keySet()) {
requestBuilder.addHeader(key, headers.get(key));
}
}
Request request = requestBuilder.build();
Response.Builder responseBuilder = chain.proceed(request).newBuilder();
if (!TextUtils.isEmpty(request.cacheControl().toString())) {
responseBuilder.removeHeader("Pragma").removeHeader("Cache-Control")
.header("Cache-Control", "public, max-age=" + request.cacheControl().maxAgeSeconds());
}
return responseBuilder.build();
}
}
根据Request
中是否有Cache-Control
来手动修改Response
,这样就做了是否缓存每次的请求结果缓存多久完全由我们自己来控制了.
然后在第一步中增加或修改
okHttpBuilder.addNetworkInterceptor(new HeaderInterceptor());
这样就能正常缓存请求了.
后续再有更新或优化,会再次更新文章~
网友评论
废话不多说,先试试楼主的方案!先行谢过了!
RetrofitManager.getInstance().create(IApi.class)
.login(etAccount.getText().toString(), etPassword.getText().toString())
.compose(RxUtil.<Result<Account>>applySchedulers(this, loadingDialog))
.subscribe(new ResultObserver<Account>() {
@Override public void handlerResult(Account account) {
setSharedPreferences("login_user", etAccount.getText().toString());
ShareData.getInstance().login(mContext, account);
skipToActivityAndFinish(HomeActivity.class, null);
}
});
上面是我登录的一次的网络请求,最近在学习kotlin 正在把框架切换过去,到时候分享给大家