Android RxJava + Retrofit 的实际应用场景

StarAlicea 8年前
   <h2>介绍</h2>    <p>关于 RxJava Retrofit 很多篇文章都有详细的说明,在这里我想分享一个具体的使用案例,在我的开源项目 <a href="/misc/goto?guid=4958988736846542220" rel="nofollow,noindex">就看天气</a> 里的实际应用。也希望跟大家探讨如何优雅的使用。</p>    <h2>前提</h2>    <p>需要知道什么是 RxJava</p>    <p>这里推荐下 扔物线写的 <a href="http://www.open-open.com/lib/view/open1452919004433.html">给 Android 开发者的 RxJava 详解</a></p>    <p>再感谢 <a href="http://www.open-open.com/lib/view/open1461505638007.html">RxJava 与 Retrofit 结合的最佳实践</a> 这篇满满的干货。</p>    <h2>实战</h2>    <h3>准备</h3>    <p>项目中用到的依赖:</p>    <pre>  compile 'io.reactivex:rxjava:1.1.0'  compile 'io.reactivex:rxandroid:1.1.0'  compile 'com.google.code.gson:gson:2.4'  compile 'com.squareup.retrofit2:retrofit:2.0.2'  compile 'com.squareup.retrofit2:converter-gson:2.0.2'  compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'  compile 'com.squareup.okhttp3:okhttp:3.0.1'  compile 'com.squareup.okhttp3:logging-interceptor:3.0.1'  compile 'com.squareup.okio:okio:1.6.0'  </pre>    <p>因为要用到网络,所以千万别忘记了这个权限。</p>    <pre>  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>  </pre>    <p>组件</p>    <p>Rx 封装的工具</p>    <p>使用 compose 操作符</p>    <p>compose() 里接收一个 Transformer 对象, Transformer 继承自 Func1<Observable<T>, Observable<R>> ,可以通过它将一种类型的 Observable 转换成另一种类型的 Observable 。</p>    <p>RxSchedulerHelper</p>    <p>封装 Rx 线程相关操作</p>    <pre>  public static <T> Observable.Transformer<T, T> rxSchedulerHelper() {      return tObservable -> tObservable.subscribeOn(Schedulers.io())          .unsubscribeOn(AndroidSchedulers.mainThread())          .observeOn(AndroidSchedulers.mainThread());  }  </pre>    <p>handleResult</p>    <p>封装 API 请求后统一处理</p>    <pre>  public static <T> Observable.Transformer<Result<T>, T> handleResult() {      return resultObservable -> resultObservable.flatMap(tResult -> {          if (tResult.code == 1) {              return createData(tResult.data);          } else {              return Observable.error(new ApiException(tResult.code));          }      });  }  </pre>    <p>RetrofitSingleton</p>    <p>自己封装了下 Retrofit 。可以学习下 <a href="/misc/goto?guid=4959673684333526930" rel="nofollow,noindex">小艾的方式</a> 。</p>    <p>自己将请求是写在该类,使用者只需要关心如何处理拿到的数据和相应的 UI 操作。</p>    <pre>  public Observable<Weather> fetchWeather(String city) {      return apiService.mWeatherAPI(city, C.KEY)          .filter(weatherAPI -> weatherAPI.mHeWeatherDataService30s.get(0).status.equals("ok"))          .map(weatherAPI -> weatherAPI.mHeWeatherDataService30s.get(0))          .compose(RxUtils.rxSchedulerHelper());  }    public Observable<VersionAPI> fetchVersion() {      return apiService.mVersionAPI(C.API_TOKEN).compose(RxUtils.rxSchedulerHelper());  }  </pre>    <p>使用</p>    <p>将 <strong> <em>网络拉取</em> </strong> 和 <strong> <em>读取缓存</em> </strong> 用 Rx 结合。</p>    <p>这里就要使用 concat 操作符, <a href="/misc/goto?guid=4959649645906935883" rel="nofollow,noindex">官方解释</a> .</p>    <p>首先看看获取网络是如何写的:</p>    <pre>  private Observable<Weather> fetchDataByNetWork() {      String cityName = Util.replaceCity(mSetting.getCityName());      return RetrofitSingleton.getInstance()          .fetchWeather(cityName)          .onErrorReturn(throwable -> {              PLog.e(throwable.getMessage());              return null;          });  }  </pre>    <p>这里的 onErrorReturn 待会儿说。</p>    <p>再来看看读取缓存的代码:</p>    <pre>  private Observable<Weather> fetchDataByCache() {      return Observable.defer(() -> {          Weather weather = (Weather) aCache.getAsObject(C.WEATHER_CACHE);          return Observable.just(weather);      });  }  </pre>    <p>然后我们将他们连接起来:</p>    <pre>  private void load() {      Observable.concat(fetchDataByNetWork(), fetchDataByCache())          .first(weather -> weather != null)          .doOnError(throwable -> {              mErroImageView.setVisibility(View.VISIBLE);              mRecyclerView.setVisibility(View.GONE);          })          .doOnNext(weather -> {              mErroImageView.setVisibility(View.GONE);              mRecyclerView.setVisibility(View.VISIBLE);          })          .doOnTerminate(() -> {              mRefreshLayout.setRefreshing(false);              mProgressBar.setVisibility(View.GONE);          })          .subscribe(observer);  }  </pre>    <p>concat + first 连接和过滤的操作实现了,网络+缓存的逻辑。</p>    <p>刚刚为什么说要在网络代码那里使用 onErrorReturn 呢?</p>    <p>如果不写,网络发生异常的话,整个流就会直接走 onError ,不会执行到读取缓存的流。</p>    <h2>结语</h2>    <p>Rx 的各种操作符的不同组合就可以实现不同的效果。本身 Rx 封装已经足够好了,我们加工的时候一定要想到是否破坏了他本身的优雅。</p>    <p>因为 Rx 是一种数据流链式结构的编程思想,我们在封装时应该不能打断其链式结构。</p>    <p>欢迎互相讨论和探讨 :)</p>    <p><img src="https://simg.open-open.com/show/5ff94b25c50dd44ce572e9f5b53726a3.jpg"></p>    <p> </p>    <p>来自: <a href="/misc/goto?guid=4959673684454552289" rel="nofollow">http://imxie.cc/2016/05/24/RxJava-Retrofit-的实际应用场景/</a></p>    <p> </p>