Hiten's Blog.

我为什么要使用RxJava

字数统计: 1.3k阅读时长: 5 min
2016/04/22 Share

接触RxJava半年左右,刚开始我一直在怀疑RxJava在Android中能做什么,上手不易,到处都是Observable让我觉得不习惯,但是研究明白了,就会被他的强大所折服。

这篇博客是我在项目中对RxJava的切实体会,不是RxJava基础知识讲解,RxJava一步一步讲解,可以看Hi大头鬼的博客。

数据变换的实际应用

场景1 http接口请求参数依赖另一个接口

比如服务器规定每个接口(除了获取时间戳接口)请求参数都需要传递服务器时间戳,时间戳请求参数和服务器时间只容错5s,不符合就要返回时间戳错误结果,但是客户端本机时间可能和服务器时间不同步,用户还可能修改本机时间,
这样就决定了不能取本地时间戳作为参数,但是每次请求目标接口前都去获取一次服务器时间戳,拿到时间戳后再去请求,这样也不好,请求次数太频繁,好在服务器为每个接口code类型,
我的解决思路是:

  • 1、创建一个静态变量,存放服务器时间与客户端时间差值TimeGap
  • 2、访问目标接口,如果返回结果是时间戳错误,进入步骤3,否则,直接处理成功或失败;
  • 3、请求时间戳,如果时间戳请求成功,保存TimeGap = serverTime-localTime,进入步骤4,否则,直接处理成功或失败;
  • 4、获取serverTime = localTime+TimeGap,再次请求目标接口,成功或者失败直接回调

用代码实现思路

  • 1、创建一个获取服务器时间戳的对象Observable getServerTime;
  • 2、运用flatMap(),由Observable对象转换为Observable,转化的目的是实现先执行时间戳Observable,后执行目标Observable
  • 3、运用concat(),连接两个Observable,调用first(),优先执行第一个observable,如果返回fasle,执行第二个observable即flatMapObservable(observable)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

//获取服务器时间戳
private Observable<ServerTime> getServerTime =...;

//由时间戳板换为目标
private <T extends HttpResult> Observable<T> flatMapObservable(final Observable<T> observable){
return getServerTime.flatMap(){
new Func1<ServerTimeModel, Observable<? extends T>>() {
@Override
public Observable<? extends T> call(ServerTime serverTime) {
//保存时间戳
TimeToken.saveTimeGap(serverTime.ServerTime()-localTime);
return observable;
}
}
}
}
//执行
private <T extends HttpResult> Observable<T> executeObservable(final Observable<T> observable){
return Observable.concat(observable,flatMapObservable(observable)).first(new Func1<T, Boolean>() {
@Override
public Boolean call(T t) {
//code ==11表示时间戳异常,返回false,表示需要进行下一个
return t.getCode() != 11;
}
})
}

场景2 多数据源处理

我们在项目中,处理多数据源是很常见的场景,比如获取首页列表数据,如果没有网络情况下我们要取持久化数据,取到网络数据还要覆盖持久化数据,而涉及到网络连接和IO操作都需要在子线程中进行,还会涉及线程调度问题;

实现思路:

  • 1、为不同数据源创建Observable对象,持久化数据源disk,网络数据源network
  • 2、network调用doOnNext()方法,就行数据持久化到本地,
  • 3、使用concat(disk,network)和first()操作符,在call()中判断数据是否可用,如果不可用则执行network。
1
2
3
4
5
6
7
8
9
10
11
Observable<Data> disk = ...;  
Observable<Data> network = ...;

Observable<Data> source = Observable
.concat(disk, network)
.first(new Func1<Data, Boolean>() {
@Override public Boolean call(Data data) {
//数据是否可用
return data.isUpToDate();
}
});

线程调度

在Android中,耗时的操作是建议在子线程中执行,比如网络请求和文件处理,切子线程中不能直接更新UI状态,系统提供了
Handler来处理,相当于子线程通知UI线程,去处理某些状态;在RxJava中,提供了subscribeOn()和observeOn()来控制线程
,observeOn是指Subscriber的线程,subscribeOn执行的是Observable所对应的线程

1
2
3
4
Observable.just(1, 2, 3, 4) // IO 线程,由 subscribeOn() 指定
.subscribeOn(Schedulers.io()) // IO线程,由 subscribeOn() 指定
.observeOn(AndroidSchedulers.mainThread) // Android 主线程,由 observeOn() 指定
.subscribe(subscriber);

这样,订阅者在主线程中,可以直接在onNext、onError方法中操作UI

与Retrofit结合

Retrofit 是 Square 的一个著名的网络请求库,同时支持okhttp和Rxjava,下面看一下如何写一个retrofit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
ublic interface ApiService {

@POST(PATH)
Observable<ApiResult<ServerTime>> getServerDateTime(@FieldMap(encoded = true) HashMap<String, String> params);

@GET(PATH)
Observable<RestEntity<UserInfo>> getUserInfo(@FieldMap(encoded = true) HashMap<String, String> params);
class Factory {
public static ApiService create() {
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.networkInterceptors().add(new StethoInterceptor());
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASEURL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(okHttpClient)
.build();
return retrofit.create(ApiService.class);
}
}
}

这是一个网络请求服务,只需调用ApiService.Factory.create().getServerDateTime()返回 Observable<ApiResult<ServerDateTime>>对象

由于时间仓促,我写的不是太详细,也没有贴出完整的源码,十分抱歉,希望这篇博客能起到抛砖引玉的作用,读者可以尝试使用RxJava创造更强大的功能!

CATALOG
  1. 1. 数据变换的实际应用
    1. 1.1. 场景1 http接口请求参数依赖另一个接口
    2. 1.2. 场景2 多数据源处理
  2. 2. 线程调度
  3. 3. 与Retrofit结合