RxJava的使用场景

这篇blog主要是讨论一些RxJava比较常用的场景,大部分例子取自我自己的一些使用经验,欢迎大家来补充。

取数据先检查缓存的场景

我们经常遇到的一个场景是,在获取数据的时候,首先检查缓存当中是否有缓存的数据,如果有,就返回缓存中的数据,否则就从数据源重新拉取数据。

使用RxJava的concat+first operator可以很容易的满足这种场景。

final Observable<String> memory = Observable.create(new Observable.OnSubscribe<String>() {
    @Override
    public void call(Subscriber<? super String> subscriber) {
        if (memoryCache != null) {
            subscriber.onNext(memoryCache);
        } else {
            subscriber.onCompleted();
        }
    }
});
Observable<String> disk = Observable.create(new Observable.OnSubscribe<String>() {
    @Override
    public void call(Subscriber<? super String> subscriber) {
        String cachePref = rxPreferences.getString("cache").get();
        if (!TextUtils.isEmpty(cachePref)) {
            subscriber.onNext(cachePref);
        } else {
            subscriber.onCompleted();
        }
    }
});

Observable<String> network = Observable.just("network");

//主要就是靠concat operator来实现
Observable.concat(memory, disk, network)
.first()
.subscribeOn(Schedulers.newThread())
.subscribe(s -> {
    memoryCache = "memory";
    System.out.println("--------------subscribe: " + s);
});

如果我们想要的效果是先从缓存取出数据,显示,然后再从数据源重新拉取数据,再显示呢?依然很简单,去掉first就可以了。concat可以保证两个Observable是按照顺序执行。

界面需要等到多个接口并发取完数据,再更新

很多时候,我们一个界面所有的数据并不是由一个接口返回的,客户端可能需要并发调用多个接口,然后等这些接口的数据都返回之后,才去显示。
RxJava的merge operator正好可以满足这种需求。

//拼接两个Observable的输出,不保证顺序,按照事件产生的顺序发送给订阅者
private void testMerge() {
    Observable<String> observable1 = DemoUtils.createObservable1().subscribeOn(Schedulers.newThread());
    Observable<String> observable2 = DemoUtils.createObservable2().subscribeOn(Schedulers.newThread());

    Observable.merge(observable1, observable2)
            .subscribeOn(Schedulers.newThread())
            .subscribe(System.out::println);
}

当然,merge有一个缺陷是它要求两个Observable中的数据类型是一致的,这堆刚才说的那个场景可能有点困难,那么我们可以考虑使用zip这个operator,
zip并去强制要求多个Observable中的数据类型是一致的。

一个接口的请求依赖另一个API请求返回的数据

举个例子,我们经常在需要登陆之后,根据拿到的token去获取消息列表。

这里用RxJava主要解决嵌套回调的问题,有一个专有名词叫Callback hell

NetworkService.getToken("username", "password")
    .flatMap(s -> NetworkService.getMessage(s))
    .subscribe(s -> {
        System.out.println("message: " + s);
    });

界面按钮需要防止连续点击的情况

RxView.clicks(findViewById(R.id.btn_throttle))
    .throttleFirst(1, TimeUnit.SECONDS)
    .subscribe(aVoid -> {
        System.out.println("click");
    });

响应式的界面

比如勾选了某个checkbox,自动更新对应的preference

SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
RxSharedPreferences rxPreferences = RxSharedPreferences.create(preferences);

Preference<Boolean> checked = rxPreferences.getBoolean("checked", true);

CheckBox checkBox = (CheckBox) findViewById(R.id.cb_test);
RxCompoundButton.checkedChanges(checkBox)
        .subscribe(checked.asAction());

复杂的数据变换

Observable.just("1", "2", "2", "3", "4", "5")
    .map(Integer::parseInt)
    .filter(s -> s > 1)
    .distinct()
    .take(3)
    .reduce((integer, integer2) -> integer.intValue() + integer2.intValue())
    .subscribe(System.out::println);//9

猜你喜欢

转载自gybin.iteye.com/blog/2270061