做者简介java
本篇来自 小河马 的投稿,分享了本身是如何进行 RxJava+Retrofit 的封装。本文的技术点天然没话说,另外对于这种模块化的思路,但愿能帮助到你们。最后提早祝你们周末愉快以及圣诞快乐!git
小河马 的博客地址:github
http://www.jianshu.com/users/14354bcb0e09web
前言缓存
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。源码已经给出请多指教!