zoukankan      html  css  js  c++  java
  • Android RxJava+Retrofit完美封装

    作者简介

    本篇来自 小河马 的投稿,分享了自己是如何进行 RxJava+Retrofit 的封装。本文的技术点自然没话说,另外对于这种模块化的思路,希望能帮助到大家。最后提前祝大家周末愉快以及圣诞快乐!

    小河马 的博客地址:

    http://www.jianshu.com/users/14354bcb0e09

    前言

    Retrofit 和 RxJava 已经出来很久了,很多前辈写了很多不错的文章,在此不得不感谢这些前辈无私奉献的开源精神,能让我们站在巨人的肩膀上望得更远。对于 RxJava 不是很了解的同学推荐你们看扔物线大神的这篇文章:

    给Android开发者的RxJava详解

    http://gank.io/post/560e15be2dca930e00da1083

    一遍看不懂就看第二遍。Retrofit的使用可以参考:

    Android Retrofit2.0使用

    http://wuxiaolong.me/2016/01/15/retrofit

    本文内容是基于 Retrofit + RxJava 做的一些巧妙的封装。参考了很多文章加入了一些自己的理解,请多指教。源码地址:

    https://github.com/Hemumu/RxSample

    先放出 build.gradle

    本文是基于 RxJava1.1.0 和 Retrofit 2.0.0-beta4 来进行的。

     

    初始化Retrofit

    新建类Api,此类就是初始化 Retrofit,提供一个静态方法初始化 Retrofit 非常简单.

    提供一个静态方法初始化 Retrofit,手动创建了 OkHttpClient 设置了请求的超时时间。并在 OkHttp 的拦截器中增加了请求头。注意这里是为所有的请求添加了请求头,你可以单独的给请求增加请求头,例如:

    和 Retrofit 初始化不同的地方就在我们添加了这两句话:

    和 Retrofit 初始化不同的地方就在我们添加了这两句话:

    变成了:

    返回值变成了 Observable,这个 Observable 不就是 RxJava 的可观察者(即被观察者)么。

     

    封装服务器请求以及返回数据

    用户在使用任何一个网络框架都只关心请求的返回和错误信息,所以对请求的返回和请求要做一个细致的封装。

    我们一般请求的返回都是像下面这样:

    如果你们的服务器返回不是这样的格式那你就只有坐下来请他喝茶,跟他好好说(把他头摁进显示器)了。大不了就献出你的菊花吧!

    对于这样的数据我们肯定要对 code 做出一些判断,不同的 code 对应不同的错误信息。所以我们新建一个 HttpResult 类,对应上面的数据结构。

    这算是所有实体的一个基类,data 可以为任何数据类型。

    我们要对所以返回结果进行预处理,新建一个 RxHelper,预处理无非就是对 code 进行判断和解析,不同的错误返回不同的错误信息,这还不简单。Rxjava 的 map 操作符不是轻松解决。

    哟,这不是轻松愉快 so seay么!对 code 进行了判断,code 为0 就做对应更新UI或者其他后续操作,不等于0就抛出异常,在 ApiException 中对 code 做处理,根据 message 字段进行提示用户。

    然而。。。RxJava 永远比你想象的强大。RxJava 中那么多操作符看到我身体不适,有个操作符 compose。因为我们在每一个请求中都会处理 code 以及一些重用一些操作符,比如用 observeOn 和 subscribeOn 来切换线程。

    RxJava提供了一种解决方案:Transformer(转换器),一般情况下就是通过使用操作符Observable.compose()来实现。具体可以参考:

    避免打断链式结构:使用.compose( )操作符

    http://www.jianshu.com/p/e9e03194199e

    新建一个 RxHelper 对结果进行预处理,代码:

    Transformer 实际上就是一个 Func1<Observable<T>, Observable<R>>,换言之就是:可以通过它将一种类型的 Observable 转换成另一种类型的 Observable,和调用一系列的内联操作符是一模一样的。

    这里我们首先使用 flatMap 操作符把 Obserable<HttpResult<T>>,转换成为 Observable<T> 在内部对code 进行了预处理。如果成功则把结果 Observable<T> 发射给订阅者。反之则把 code 交给 ApiException 并返回一个异常,ApiException 中我们对 code 进行相应的处理并返回对应的错误信息。

    最后调用了频繁使用的 subscribeOn() 和 observeOn() 以及 unsubscribeOn()

     

    处理ProgressDialog

    在 Rxjava 中我们什么时候来显示 Dialog 呢。一开始觉得是放在 Subscriber<T> 的 onStart 中。onStart 可以用作流程开始前的初始化。然而  onStart() 由于在subscribe() 发生时就被调用了,因此不能指定线程,而是只能执行在  subscribe() 被调用时的线程。所以 onStart 并不能保证永远在主线程运行。

    怎么办呢?

    千万不要小看了 RxJava,与 onStart() 相对应的有一个方法 doOnSubscribe(),它和  onStart() 同样是在 subscribe() 调用后而且在事件发送前执行,但区别在于它可以指定线程。默认情况下,doOnSubscribe() 执行在 subscribe() 发生的线程;而如果在 doOnSubscribe() 之后有subscribeOn() 的话,它将执行在离它最近的 subscribeOn() 所指定的线程。

    可以看到在 RxHelper 中看到我们调用了两次 subscribeOn,最后一个调用也就是离doOnSubscribe() 最近的一次 subscribeOn 是指定的 AndroidSchedulers.mainThread() 也就是主线程。这样我们就就能保证它永远都在主线运行了。这里不得不感概 RxJava 的强大。

    这里我们自定义一个类 ProgressSubscriber 继承 Subscriber<T>

    初始化 ProgressSubscriber 新建了一个我们自己定义的 ProgressDialog 并且传入一个自定义接口 ProgressCancelListener。此接口是在 SimpleLoadDialog 消失 onCancel 的时候回调的。用于终止网络请求。

    ProgressSubscriber 其他就很简单了,在 onCompleted() 和 onError() 的时候取消 Dialog。需要的时候调用 showProgressDialog 即可。

     

    处理数据缓存

    服务器返回的数据我们肯定要做缓存,所以我们需要一个 RetrofitCache 类来做缓存处理。

    几个参数注释上面已经写得很清楚了,不需要过多的解释。这里我们先取了一个 Observable<T> 对象 fromCache,里面的操作很简单,去缓存里面找个 key 对应的缓存,如果有就发射数据。

    在 fromNetwork 里面做的操作仅仅是缓存数据这一操作。最后判断如果强制刷新就直接返回 fromNetwork反之用 Observable.concat() 做一个合并。concat 操作符将多个 Observable 结合成一个 Observable并发射数据。这里又用了 first()fromCache 和 fromNetwork 任何一步一旦发射数据后面的操作都不执行。

    最后我们新建一个 HttpUtil 用来返回用户关心的数据,缓存,显示Dialog在这里面进行:

    Activity生命周期管理

    基本的网络请求都是向服务器请求数据,客户端拿到数据后更新UI。但也不排除意外情况,比如请求回数据途中 Activity 已经不在了,这个时候就应该取消网络请求。

    要实现上面的功能其实很简单,两部分

    • 随时监听 Activity(Fragment) 的生命周期并对外发射出去; 在我们的网络请求中,接收生命周期

    • 并进行判断,如果该生命周期是自己绑定的,如 Destory,那么就断开数据向下传递的过程

    实现以上功能需要用到 Rxjava 的 Subject 的子类 PublishSubject

    在你的 BaseActivity 中添加如下代码:

    这样的话,我们把所有生命周期事件都传给了 PublishSubject 了,或者说 PublishSubject 已经接收到了并能够对外发射各种生命周期事件的能力了。

    现在我们要让网络请求的时候去监听这个 PublishSubject,在收到相应的生命周期后取消网络请求,这又用到了我们神奇的 compose(),我们需要修改 handleResult 代码如下:

    调用的时候增加了两个参数一个是 ActivityLifeCycleEvent 其实就是一些枚举表示 Activity 的生命周期

    public enum ActivityLifeCycleEvent {
       CREATE,
       START,
       RESUME,
       PAUSE,
       STOP,
       DESTROY
    }

    另外一个参数就是我们在 BaseActivity 添加的 PublishSubject,这里用到了 takeUntil(),它的作用是监听我们创建的 compareLifecycleObservable

    compareLifecycleObservable 中就是判断了如果当前生命周期和 Activity 一样就发射数据,一旦compareLifecycleObservable 对外发射了数据,就自动把当前的Observable(也就是网络请求的Observable)停掉。

    当然有个库是专门针对这种情况的,叫

    RxLifecycle

    https://github.com/trello/RxLifecycle

    不过要继承他自己的 RxActivity,当然这个库不只是针对网络请求,其他所有的Rxjava都可以。有需要的可以去看看。

    最后新建一个 ApiService 存放我们的请求:

     

    使用起来就超级简单了:

    具体很多东西都可以在使用的时候具体修改,比如缓存我用的 Hawk。Dialog 是我自己定义的一个 SimpleLoadDialog。源码已经给出请多指教!

  • 相关阅读:
    放缩ImageView
    2017/5/3 afternoon
    2017/5/3 morning
    2017/5/2 afternoon
    2017/5/2 morning
    2017/4/28 afternoon
    2017/4/28 morning
    2017/4/27 afternoon
    2017/4/27 morning
    2017/4/26 afternoon
  • 原文地址:https://www.cnblogs.com/huolongluo/p/6495185.html
Copyright © 2011-2022 走看看