Retrofit+RxJava总结

ElviraCowle 8年前
   <p>上次发布的文章 Retrofit2.0+RxJava初步 简单介绍了Retrofit2.0与RxJava结合使用, 前段时间在公司的项目中引入了Retrofit框架,今天对项目中碰到的问题和一些常见的使用场景做个总结。</p>    <p>本文主要包含以下2个内容:</p>    <ul>     <li>HttpResult统一处理返回结果</li>     <li>网络请求与生命周期绑定</li>     <li>retrofit缓存及日志</li>    </ul>    <h3><strong>统一处理返回结果</strong></h3>    <p>在项目中一般与后台定义好返回的json数据结构, 我们的格式如下:</p>    <pre>  <code class="language-java">{      "code": 0,      "data": ...,      "msg": "success"  }</code></pre>    <p>所以,在项目的service层中,统一判断code值, 如果错误, 抛出异常, 如果正确,再把data结构返回给上层界面层处理。</p>    <p>首先,定义一个HttpResult对象:</p>    <pre>  <code class="language-java">public class HttpResult<T> {      public int code;      public String msg;      public T data;  }</code></pre>    <p>第二步, 我们在上一篇文章可以看到, 定义一个请求的方法如下:</p>    <pre>  <code class="language-java">@GET("shots/{id}/comments")  Observable<HttpResult<Comments>> getComments(@Path("id") int id, @Query("page") String page);</code></pre>    <p>对于如何将HttpResult对象,进行解析,成功的话传回Comments结构, 失败则抛出异常进行处理。</p>    <p>这里需要用到RxJava的一个功能: <strong>map()</strong> , 它是RxJava的一个核心功能之一, 这个方法提供了对事件序列进行变换的支持, 也就是说它可以将传入的一个对象转化成另外一个对象, 它的参数是一个“FunX”(x是数字,代表有几个参数)。</p>    <p>例如想要实现HttpResult<T> --> T 的转换, 我们是这样实现的:</p>    <pre>  <code class="language-java">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;      }  }</code></pre>    <p>有了上面的转化, 为了上面的转化适用于所有的接口请求, 我们得将上述转化用transform封装起来, 然后使用compose将Observable自身进行变化, 代码如下:</p>    <pre>  <code class="language-java">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;  }</code></pre>    <p>最后, 完成Observable的转化:</p>    <pre>  <code class="language-java">return ApiService.getComments(id, page).compose(this.<Comments>lifts());</code></pre>    <h3><strong>生命周期绑定</strong></h3>    <p>· 内存泄漏的问题</p>    <p>当我们在调用网络请求的时候, 会生成一个subscription对象, 如果里面引用了context或者其他的view对象, 而在Activity生命周期结束的时候又没有及时结束, 那么很容造成内存泄漏的问题。</p>    <p>这里用了CompositeSubscription解决这个问题:</p>    <pre>  <code class="language-java">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;      }  }</code></pre>    <p>上述代码在基类BaseActivity中实现, 每次调用网络请求的时候,都通过addSubscription() 方法。</p>    <h3><strong>缓存及日志</strong></h3>    <p>retrofit缓存及日志功能网上代码比较多了, 就简单说一下,都是通过拦截器实现的 :</p>    <ul>     <li>缓存 <pre>  <code class="language-java">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();        }    }  };</code></pre> 添加缓存拦截的时候, 最好用两种方式都添加一下, 仅仅是addInterceptor是不够的: <pre>  <code class="language-java">.addNetworkInterceptor(cacheInterceptor)     .addInterceptor(cacheInterceptor)</code></pre> </li>    </ul>    <p> </p>    <ul>     <li> <p><strong>参考</strong></p> <p><a href="/misc/goto?guid=4959726459591482276" rel="nofollow,noindex">给Android开发者的RxJava详解</a></p> <p><a href="http://www.jianshu.com/p/e7473d01f1aa?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io" rel="nofollow,noindex">http://www.jianshu.com/p/e7473d01f1aa?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io</a></p> <a href="/misc/goto?guid=4959726459767097981" rel="nofollow,noindex">http://www.jianshu.com/p/bd758f51742e</a></li>    </ul>    <p> </p>    <p>来自:http://www.jianshu.com/p/fbc6848deffa</p>    <p> </p>