Retrofit+RxJava總結
上次發布的文章 Retrofit2.0+RxJava初步 簡單介紹了Retrofit2.0與RxJava結合使用, 前段時間在公司的項目中引入了Retrofit框架,今天對項目中碰到的問題和一些常見的使用場景做個總結。
本文主要包含以下2個內容:
- HttpResult統一處理返回結果
- 網絡請求與生命周期綁定
- retrofit緩存及日志
統一處理返回結果
在項目中一般與后臺定義好返回的json數據結構, 我們的格式如下:
{
"code": 0,
"data": ...,
"msg": "success"
}
所以,在項目的service層中,統一判斷code值, 如果錯誤, 拋出異常, 如果正確,再把data結構返回給上層界面層處理。
首先,定義一個HttpResult對象:
public class HttpResult<T> {
public int code;
public String msg;
public T data;
}
第二步, 我們在上一篇文章可以看到, 定義一個請求的方法如下:
@GET("shots/{id}/comments")
Observable<HttpResult<Comments>> getComments(@Path("id") int id, @Query("page") String page);
對于如何將HttpResult對象,進行解析,成功的話傳回Comments結構, 失敗則拋出異常進行處理。
這里需要用到RxJava的一個功能: map() , 它是RxJava的一個核心功能之一, 這個方法提供了對事件序列進行變換的支持, 也就是說它可以將傳入的一個對象轉化成另外一個對象, 它的參數是一個“FunX”(x是數字,代表有幾個參數)。
例如想要實現HttpResult<T> --> T 的轉換, 我們是這樣實現的:
private class HttpResultFunc<T> implements Func1<HttpResult<T>, T> {
@Override
public T call(HttpResult<T> httpResult) {
if (httpResult == null) {
throw new HttpException(400, "網絡錯誤");
} else if (!httpResult.isSuccess()) {
String msg = httpResult.msg != null ? httpResult.msg : "未知錯誤";
throw new HttpException(httpResult.code, msg);
} else
return httpResult.data;
}
}
有了上面的轉化, 為了上面的轉化適用于所有的接口請求, 我們得將上述轉化用transform封裝起來, 然后使用compose將Observable自身進行變化, 代碼如下:
private final HttpResultFunc<Object> func = new HttpResultFunc<>();
private class RetrofitTransformer implements Transformer {
@Override
public Object call(Object o) {
Observable observable = ((Observable) o);
return observable.subscribeOn(io())
.unsubscribeOn(io())
.observeOn(AndroidSchedulers.mainThread())
.onErrorReturn(errorFunc)
.map(func);
}
}
protected <T> Observable.Transformer<HttpResult<T>, T> lifts() {
return (Observable.Transformer<HttpResult<T>, T>) transformer;
}
最后, 完成Observable的轉化:
return ApiService.getComments(id, page).compose(this.<Comments>lifts());
生命周期綁定
· 內存泄漏的問題
當我們在調用網絡請求的時候, 會生成一個subscription對象, 如果里面引用了context或者其他的view對象, 而在Activity生命周期結束的時候又沒有及時結束, 那么很容造成內存泄漏的問題。
這里用了CompositeSubscription解決這個問題:
mCompositeSubscription = new CompositeSubscription();
public void addSubscription(Subscription subscription) {
if (mCompositeSubscription != null && mCompositeSubscription.isUnsubscribed()) {
mCompositeSubscription.add(subscription);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mCompositeSubscription != null && !mCompositeSubscription.isUnsubscribed()) {
mCompositeSubscription.unsubscribe();
mCompositeSubscription = null;
}
}
上述代碼在基類BaseActivity中實現, 每次調用網絡請求的時候,都通過addSubscription() 方法。
緩存及日志
retrofit緩存及日志功能網上代碼比較多了, 就簡單說一下,都是通過攔截器實現的 :
- 緩存
private static Interceptor cacheInterceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); if (!HttpUtils.isNetworkConnected()) { request = request.newBuilder() .cacheControl(CacheControl.FORCE_CACHE) .build(); } Response response = chain.proceed(request); if(HttpUtils.isNetworkConnected()){ //有網的時候讀接口上的@Headers里的配置 String cacheControl = request.cacheControl().toString(); return response.newBuilder() .header("Cache-Control", cacheControl) .removeHeader("Pragma") .build(); }else{ return response.newBuilder() .header("Cache-Control", "public, only-if-cached, max-stale=2419200") .removeHeader("Pragma") .build(); } } };
.addNetworkInterceptor(cacheInterceptor) .addInterceptor(cacheInterceptor)
-
參考
http://www.jianshu.com/p/e7473d01f1aa?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io
http://www.jianshu.com/p/bd758f51742e
來自:http://www.jianshu.com/p/fbc6848deffa