RxJava2变化
RxJava2(下面统称为rx2)按照Reactive-Streams specification规范进行了重写,因而与RxJava1(下面统称为rx1)相比有了不少的变化。
引用包名不同
import时的包名由rx.*
变成了io.reactive.*
禁止接受null
在rx1中,Observable可以发射任何类型的值,包括null,因此我们不用当心null的问题,即使是像这样使用也不会有任何问题:Observable.just(null)
, 但在rx2中不再允许发射null,否则会抛出了NullPointerException,因此在使用rx2时就必须先做好null值的判断,避免NPE。Observable与Flowable
在rx1中,比较让人诟病的就是背压问题,rx1部分支持背压,而且不能很好的处理背压问题(即被观察者发射速度太快(例如一些UI事件)以至于它的操作符或订阅者不能及时处理相关消息,进而抛出MissingBackpressureException),因而需要开发者自己控制上流的发射速度或者在下游做好限制处理。不过大部分时候,我们都不需要考虑背压问题,因此,rx2便增加了一个新的被观察者Flowable, Flowable的主要特点便是支持背压,而原先的Observable便更改为不再支持背压了,因此我们便可以根据自己的需求来选择合适的被观察者。Observer与Suscriber
与Observable与Flowable对应,它两的订阅者分别是Observer与Suscriber, 即Observable.subscribe(Observer)
和Flowable.subscribe(Subscriber)
。因而,Observable在create时不再Subscriber参数,而是一个ObservableEmitter, 即Observable.create(new ObservableOnSubscribe<Integer>() { @Override public void subscribe(ObservableEmitter<Integer> emitter) throws Exception { } })
遵循reactive-streams,取消了原先的Suscriber,改用reactive-streams的Suscriber,同时Observer与之保持一致,因此rx2的Observer和Suscriber与rx1的有点不同,即
onNext, onError, onComplete
依然存在着,但onStart
便不存在了,不过新的onSubscribe
方法其实也可以替代原先的onStart
,若依然想用onStart
,rx2也有提供几个实现Suscriber接口又包含该方法的抽象类:DefaultSubscriber
,ResourceSubscriber
,DisposableSubscriber
。Disposable
在rx2中,由于引入了reactive-streams,而reactive-streams中已经存在了Subscription, 因而将rx1的Subscription改名为Disposable,依然用来判断和取消订阅关系。
不过,为了和reactive-streams保持一致,Observable.subscribe(Observer)
和Flowable.subscribe(Subscriber)
这两种方式不再返回一个Disposable(rx1会返回一个Subscription)对象,取而代之的是提供了subscribe的几个新重载函数,它们便会返回对应的Disposable,分别是public final Disposable subscribe() public final Disposable subscribe(Consumer<? super T> onNext) public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError) public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete) public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete, Consumer<? super Disposable> onSubscribe) //直接订阅Observer或Subscriber返回void public final void subscribe(Observer<? super T> observer) public final void subscribe(Subscriber<? super T> s)
Action和Function变更
rx2根据Java8的命名规范,更改了Action和Function的命名,具体如下:
(Action)rx1 | rx2 |
---|---|
Action0 | Action |
Action1 | Consumer |
Action2 | BiConsumer |
Action3-Action9 | 取消 |
ActionN | Consumer<Object[]> |
(Function)rx1 | rx2 |
---|---|
Func0 | 取消 |
Func1 | Function |
Func2 | BiFunction |
Func3 - Func9 | Function3 - Function9 |
FuncN | Function<Object[], R> |
Func1<T, Boolean> | Predicate<T> |
同时,在rx2中,所有的Action和Function都抛出了异常,因此我们并不得不去捕获这些异常了。
7. 一些常用方法的变更
from
rx1中,对于数组,列表和Future类型的数据源都采用from进行获取,而rx2对其进行了细 分,分别拆分为fromArray
, fromIterable
和 fromFuture
, 并添加 了一个fromPublisher
, 至于 fromCallable
则保持不变。
其他
带有2-9个参数的startWith统一改为startWithArray
toList和toMap等的返回值变成Single类型,并添加toObservable方便转化
toBlocking().y变成blockingY(),例如toBlocking().firstOrDefault(defaultValue)
变成 blockingFirst(defaultValue)
。
以上便是rx2中比较常见的一些变化,其他变化具体请查看RxJava2的变化。
NPE适配技巧
由于rx2不再允许接受null值,因此在创建流之前必须先判断该源头数据是否为null,但若是每次创建新的rx流都需要判断一次,特别是对于那些从rx1升到rx2上的项目,由于之前不需考虑null值问题,此时来添加判断,必定是一件十分繁琐又无趣的事,因而我们可以通过创建一个NullCheckUtil工具类在处理这些源头数据,进而大大简化每次创建rx流时的工作。主要分为以下两种情况。
源头为单一实体
例如从缓存中获取某个对象,在未保存下来之前肯定是null,也有可能保存了null或保存不成功,因此必须先判断好再创建rx流。对于这种我们认为已经存在的对象,我们通常会采用Observable.just()来开始一个rx流,因此我们可以为该对象添加个外壳,即采用Java8中的Optional来做封装(因为Java8以下的Optional要求Android的API必须在24及以上,因此不要导入Java8以下的,当然若是不想用Java8,也可以直接写个简单的外壳用来封装),然后通过optional.get()来获取我们传入的值,例如:Observable.just(Optional.ofNullable(cache)) .subscribe(new Consumer<Optional<Object>>() { @Override public void accept(Optional<Object> optional) throws Exception { // 通过optional.isPresent()判断是否为null,再通过optional.get() 获取cache } });
源头为列表型实体
例如从API请求一个数据列表,首先获取到的response可能为null,其次response里的数据可能为null,当然如果是有多层嵌套的数据的话,里面的列表也有可能为null,因此可以提供几个统一的处理方法来规避这些问题。先贴上NullCheckUtil的部分代码:
public interface Function<T, R> {
R apply(T var);
}
// ①
public static <T> List<T> elvisList(List<T> t) {
if (t == null) return Collections.emptyList();
return t;
}
// ②
public static <T, R> List<R> elvisList(T t, Function<T, List<R>> ifNotNull) {
List<R> list = t == null ? new ArrayList<R>() : ifNotNull.apply(t);
if (list == null) list = Collections.emptyList();
return list;
}
// ③
public static <T, R> Observable<R> observableElvisList(T t, Function<T, List<R>> ifNotNull) {
List<R> list = t == null ? new ArrayList<R>() : ifNotNull.apply(t);
if (list == null) list = Collections.emptyList();
return Observable.fromIterable(list);
}
整个思路其实很简单,就是判断是否为null,若是null则创建一个新的空列表。方法①最为简单就不说了,方法②适用于数据源为嵌套于某个对象里面的列表,至于如何获取该列表,便通过Function接口由外部提供,方法③则是在②的基础上直接返回一个Observable,其实对于我们这里说的rx2来说,可以直接使用方法③作为列表型数据源的处理,此时我们便可以这样使用:
NullCheckUtil.observableElvisList(apiResponseData, data -> data.list).subscribe();
当然这里采用的是lambda的写法,所以看起来非常整洁,这里也强力建议使用lambda。这样我们便不需要再去考虑数据源是否为null的问题了,可以无忧无虑的直接创建rx流,是不是极其方便简单呢,当然,如果有其他通用的操作,例如map/filter/toList/compose之类的,也可以直接抽取到公共的工具类里,这样便可以进一步简化代码了。