美文网首页Android Dev技术干货Android知识
RxJava + Retrofit 的实际应用场景

RxJava + Retrofit 的实际应用场景

作者: 谢三弟 | 来源:发表于2016-05-24 17:44 被阅读7691次

    介绍

    关于RxJava Retrofit很多篇文章都有详细的说明,在这里我想分享一个具体的使用案例,在我的开源项目 就看天气 里的实际应用。也希望跟大家探讨如何优雅的使用。

    前提

    需要知道什么是 RxJava

    这里推荐下 扔物线写的 给 Android 开发者的 RxJava 详解

    再感谢 RxJava 与 Retrofit 结合的最佳实践 这篇满满的干货。

    实战

    准备

    项目中用到的依赖:

    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'
    

    因为要用到网络,所以千万别忘记了这个权限。

    <uses-permission android:name="android.permission.INTERNET"/>
    

    组件

    Rx 封装的工具

    使用compose操作符

    compose()里接收一个Transformer对象,Transformer继承自Func1<Observable<T>, Observable<R>>,可以通过它将一种类型的Observable转换成另一种类型的Observable

    RxSchedulerHelper

    封装 Rx 线程相关操作

    public static <T> Observable.Transformer<T, T> rxSchedulerHelper() {
        return tObservable -> tObservable.subscribeOn(Schedulers.io())
            .unsubscribeOn(AndroidSchedulers.mainThread())
            .observeOn(AndroidSchedulers.mainThread());
    }
    
    handleResult

    封装 API 请求后统一处理

    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));
            }
        });
    }
    

    RetrofitSingleton

    自己封装了下 Retrofit。可以学习下小艾的方式

    自己将请求是写在该类,使用者只需要关心如何处理拿到的数据和相应的 UI 操作。

    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());
    }
    

    使用

    网络拉取读取缓存用 Rx 结合。
    这里就要使用 concat 操作符,官方解释.

    首先看看获取网络是如何写的:

    private Observable<Weather> fetchDataByNetWork() {
        String cityName = Util.replaceCity(mSetting.getCityName());
        return RetrofitSingleton.getInstance()
            .fetchWeather(cityName)
            .onErrorReturn(throwable -> {
                PLog.e(throwable.getMessage());
                return null;
            });
    }
    

    这里的 onErrorReturn 待会儿说。

    再来看看读取缓存的代码:

    private Observable<Weather> fetchDataByCache() {
        return Observable.defer(() -> {
            Weather weather = (Weather) aCache.getAsObject(C.WEATHER_CACHE);
            return Observable.just(weather);
        });
    }
    

    然后我们将他们连接起来:

    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);
    }
    

    concat + first 连接和过滤的操作实现了,网络+缓存的逻辑。

    刚刚为什么说要在网络代码那里使用 onErrorReturn 呢?

    如果不写,网络发生异常的话,整个流就会直接走 onError ,不会执行到读取缓存的流。

    结语

    Rx 的各种操作符的不同组合就可以实现不同的效果。本身 Rx 封装已经足够好了,我们加工的时候一定要想到是否破坏了他本身的优雅。

    因为 Rx 是一种数据流链式结构的编程思想,我们在封装时应该不能打断其链式结构。

    欢迎互相讨论和探讨 :)

    相关文章

      网友评论

      • 进击的鱼儿:是这样的,我们服务器放回的json里面都带有了resultCode用来判断请求的状态是成功或是失败,然后我用rxjava的map进行统一的处理,在里面对resultCode进行了判断,失败的话我throw一个自定义异常,这样如果失败的话就可以在onError里面获取到自定义的异常信息,所以我想知道用了这个onErrorReturn后我们用的这个自定义异常还能在onError里面获取到吗?谢谢解答!
        进击的鱼儿:@RyuJin 谢谢三哥!
        谢三弟:@RyuJin http://imxie.cc/2016/06/01/tao-lun-Rx-onError/ 可以看看这篇?
        谢三弟:onErrorReturn 就不会走 onError 了 除非它后续的操作还产生了 error
      • 进击的鱼儿:你好,我想问一下写了onErrorReturn后没有网络的时候就会有缓存,不然的话就会直接走onError,那么如果我写了onErrorReturn是不是不论发生什么都不会走onError了吗?
        谢三弟:@RyuJin 其实这里就相当于单独给网络写onError方法。
      • wavever:温心~
      • 84b10d474c93:handleResult() 这个方法 貌似你的工程里没有出现过.
        谢三弟: @jave1987 对…因为和风天气不是 restful …没办法用到,我在团队项目用到了这个统一处理 code
      • WYWT:Observable.concat(fetchDataByNetWork(), fetchDataByCache())  这不应该是先拿缓存,再拿网络吗? 顺序有问题吧
        eveo: :smile: 我现在是先显示缓存,然后刷新。就不会出现空白
        谢三弟: @Neexz 为了每次用户能看最新的…😐我就这样做了,根据需求来吧?毕竟天气还是有实时性,只是保证了没有网或者网络出错还有上次内容可看
      • 周撒飞:CC. 我一打开简书就看到你:joy::joy::joy:
        谢三弟: @戴皮 哈哈哈哈
      • _大毛_:不错不错,学习了
      • 天青色等煙雨_而我在等妳:http://ac-mhke0kuv.clouddn.com/f1c715cd0f4259624c4b.jpg
        哎呦,不错哦,这是谁啊? :smile:
        小胖0_0:@天青色等煙雨_而我在等妳 温心女神
      • 莫离境:用到网络不是Internet吗
        谢三弟:@CastleVong 对对= = 看错了 做大死了

      本文标题:RxJava + Retrofit 的实际应用场景

      本文链接:https://www.haomeiwen.com/subject/idvzrttx.html