通过写一个自定义的Operator可以更好的理解RxJava中的流式传递机制。
先借用扔物线的给 Android 开发者的 RxJava 详解 中的一段内容:
这些变换虽然功能各有不同,但实质上都是针对事件序列的处理和再发送。而在 RxJava 的内部,它们是基于同一个基础的变换方法: lift(Operator)。首先看一下 lift() 的内部实现(仅核心代码):
// 注意:这不是 lift() 的源码,而是将源码中与性能、兼容性、扩展性有关的代码剔除后的核心代码。
// 如果需要看源码,可以去 RxJava 的 GitHub 仓库下载。
public <R> Observable<R> lift(Operator<? extends R, ? super T> operator) {
return Observable.create(new OnSubscribe<R>() {
@Override
public void call(Subscriber subscriber) {
Subscriber newSubscriber = operator.call(subscriber);
newSubscriber.onStart();
onSubscribe.call(newSubscriber);
}
});
}
这段代码很有意思:它生成了一个新的 Observable 并返回,而且创建新 Observable 所用的参数 OnSubscribe 的回调方法 call() 中的实现竟然看起来和前面讲过的 Observable.subscribe() 一样!然而它们并不一样哟~不一样的地方关键就在于第二行 onSubscribe.call(subscriber) 中的 onSubscribe 所指代的对象不同(高能预警:接下来的几句话可能会导致身体的严重不适)——
subscribe() 中这句话的 onSubscribe 指的是 Observable 中的 onSubscribe 对象,这个没有问题,但是 lift() 之后的情况就复杂了点。
当含有 lift() 时:
1.lift() 创建了一个 Observable 后,加上之前的原始 Observable,已经有两个 Observable 了;
2.而同样地,新 Observable 里的新 OnSubscribe 加上之前的原始 Observable 中的原始 OnSubscribe,也就有了两个 OnSubscribe;
3.当用户调用经过 lift() 后的 Observable 的 subscribe() 的时候,使用的是 lift() 所返回的新的 Observable ,于是它所触发的 onSubscribe.call(subscriber),也是用的新 Observable 中的新 OnSubscribe,即在 lift() 中生成的那个 OnSubscribe;
4.而这个新 OnSubscribe 的 call() 方法中的 onSubscribe ,就是指的原始 Observable 中的原始 OnSubscribe ,在这个 call() 方法里,新 OnSubscribe 利用 operator.call(subscriber) 生成了一个新的 Subscriber(Operator 就是在这里,通过自己的 call() 方法将新 Subscriber 和原始 Subscriber 进行关联,并插入自己的『变换』代码以实现变换),然后利用这个新 Subscriber 向原始 Observable 进行订阅。
这样就实现了 lift() 过程,有点像一种代理机制,通过事件拦截和处理实现事件序列的变换。精简掉细节的话,也可以这么说:在 Observable 执行了 lift(Operator) 方法之后,会返回一个新的 Observable,这个新的 Observable 会像一个代理一样,负责接收原始的 Observable 发出的事件,并在处理后发送给 Subscriber。
操作符的目的本质上是将原Observable发射的item进行改变后继续发射。从表现形式上看就是将一个Observable(比如将其称为ob1)转为另一个Observable(比如将其称为ob2),转换后,ob2发射的条目类型(比如称其为t2)与ob1发射的条目类型(比如称其为t1)不相同。如果按照流式的写法,订阅者将订阅ob2发射的t2条目:
ob1.操作符().subscribe(new Subscriber<t2>(){...});
这种流式的写法是如何得到的实现的?其实每一个操作符内部都会执行一个转换操作,把订阅t2的原始订阅者转为一个订阅t1的新订阅者,然后在新订阅者内部将收到的t1条目转为t2条目后传递给原始订阅者。类似的操作如下:
//每一个操作都需要继承在Operator接口
MyOpt implements Operator<t2,t1>{
@Override
public Subscriber<? super t1> call(Subscriber<? super t2> 原始订阅者) {
//生成一个新订阅者
return new Subscriber<t1>(原始订阅者) {
@Override
public void onCompleted() {
原始订阅者.onCompleted();
}
@Override
public void onError(Throwable e) {
原始订阅者.onError(e);
}
@Override
public void onNext(t1) {
t2 = f(t1);//将收到的t1转为t2
原始订阅者.onNext(t2);
}
};
}
}
通过这个转换就可以实现流式的调用了。
实际写一个简单的示例,将一个发射Integer的Observable转化为发射String的Observable:
public class MyStringOpt implements Observable.Operator<String,Integer>{
@Override
public Subscriber<? super Integer> call(Subscriber<? super String> subscriber) {
return new Subscriber<Integer>(subscriber) {
@Override
public void onCompleted() {
subscriber.onCompleted();
}
@Override
public void onError(Throwable e) {
subscriber.onError(e);
}
@Override
public void onNext(Integer integer) {
subscriber.onNext(String.valueOf(integer));
}
};
}
}
自定义操作符MyStringOpt将一个本来订阅String的订阅者要转为订阅Integer的订阅者。
然后利用MyStringOpt实现流式调用:
Observable<String> ob = Observable.just(1, 2, 3, 4).cast(Integer.class).lift(new MyStringOpt());
ob.subscribe(v-> System.out.println(v.getClass().getSimpleName()+": "+v));
执行的结果为:
String: 1
String: 2
String: 3
String: 4