lift()
方法是RxJava中所有操作符的基礎,可以通過它做各種各樣的變化。弄清楚它的原理,也方便我們理解其他操作符。首先先看幾個相關接口。
Func1 接口
public interface Func1<T, R> extends Function {
R call(T t);
}
Func1
接口會按照泛型參數(shù)的順序傳入T
,并返回R
。
Operator 接口
public interface Operator<R, T> extends Func1<Subscriber<? super R>, Subscriber<? super T>>
按照Func1
接口的定義,Operator
接口會傳入一個Subscriber<? super R>
參數(shù),并返回一個Subscriber<? super T>
。
關于Operator和lift()中泛型順序的問題
也許有人(is me)第一眼看到Observable<T>
,Operator<R, T>
,Func1<T, R>
這幾個類的泛型參數(shù),頭都大了,關鍵是Operator
的泛型參數(shù)順序為什么是R, T
,而不是T, R
?
其實這里不需要關心順序是什么,只需要記住Operator<R, T>
是按照泛型參數(shù)的順序,傳入一個Subscriber<R>
參數(shù),并返回一個Subscriber<T>
,寫成Operator<A, B>
或者Operator<M, N>
是沒有任何區(qū)別的。
lift()調用流程
首先需要記住lift()
方法是在一個已有Observable
上調用的。
lift()
方法核心代碼:
public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) {
return new Observable<R>(new OnSubscribe<R>() {
@Override
public void call(Subscriber<? super R> o) {
Subscriber<? super T> st = operator.call(o);
st.onStart();
// 這里的onSubscribe是調用lift方法的Observable中的onSubscribe
onSubscribe.call(st);
}
});
}
根據代碼的調用流程來分析:
1、假設已有一個Observable<T>
,調用lift()
方法,生成一個Observable<R>
,此時就有了兩個Observable
和兩個OnSubscribe
對象。
2、然后調用Observable<R>
的subscribe()
方法,傳入一個Subscriber<R>
對象,此時觸發(fā)Observable<R>.onSubscribe.call()
方法,也就是上面lift()
方法中的call()
方法。
3、在該方法中會調用onSubscribe.call()
方法,注意這個onSubscribe
是Observable<T>
中的那個OnSubscribe<T>
對象,它需要傳入一個Subscriber<T>
對象,這個對象是通過operator.call()
方法生成的。正是這個Operator
對象將兩個Subscriber
對象關聯(lián)起來,OnSubscribe<T>
在執(zhí)行Subscriber<T>.onNext(T t)
方法的時候也會執(zhí)行Subscriber<R>.onNext(R r)
,而這里從T
變成R
,正好用到了傳到Operator
中的參數(shù)Func1<T, R>
。
4、如果具體化一點,上面的Observable<T>
就是事件源,對它進行lift()
變換得到新的Observable<R>
,這個新的Observable
的回調已經固定,相當于是一個模板(也就是上面lift()
方法中的call()
方法)。這時調用subscribe()
,傳入的Subscriber<R>
是用戶定義的事件監(jiān)聽者,但它監(jiān)聽的是新的Observable<R>
,這個Observable
的回調是固定的,它并不能產生新事件,所以得靠事件源Observable<T>
。這個時候Operator
生成一個中間的Subscriber<T>
對象,該對象的作用就是接收事件源的事件,并將事件轉給用戶定義的Subscriber
。這個Subscriber<T>
并沒有消耗事件,而是起著一個代理的作用。所以Operator
可以看做是一個生成代理的工具類。在這個轉發(fā)過程中有一個數(shù)據類型的變化過程,也是通過Operator
的轉換器Func1實現(xiàn)的,想怎樣轉換數(shù)據,也是用戶定義后傳到Operator
中的。
小結
1、我們需要把Observable
的調用看做一條流。
2、對于Observable<T> -> Observable<R>
這個變化,訂閱者為Subscriber<R>
,在subscriber()
方法調用后,流的順序為倒序的,即從Observable<R> -> Observable<T>
,因為我們始終需要調用最開始的事件源。為了滿足這個需求,會通過Operator<R, T>
這個代理工具生成一個代理Subscriber<T>
,這也解釋了為什么在聲明Operator
時泛型參數(shù)的順序寫為R, T
,正好可以和這一變化對應起來,用相同的泛型參數(shù)更便于理解。這樣準備工作就都做好了。
3、Observable<T>
開始向Subscriber<T>
發(fā)送事件,發(fā)送的參數(shù)類型為T
,這時候通過轉換器Func1
將T
變成R
,這樣就能順利的通過代理Subscriber<T>
將事件發(fā)送給Subscriber<R>
了。
4、所以流的路線為Observable<R> -> Observable<T> -> Subscriber<T> -> Subscriber<R>
。一條線分成兩部分,前半部分為準備工作,后半部分為執(zhí)行操作。
下圖是lift()
的過程,其中虛線箭頭代表生成,實線箭頭代表調用。也可以參考 扔物線 - 給 Android 開發(fā)者的 RxJava 詳解 中的配圖。
map()方法
map()
方法是RxJava中使用lift()
最簡單的方法,如果上面lift()
方法過于抽象,可以通過該方法來加深理解。
public final <R> Observable<R> map(Func1<? super T, ? extends R> func) {
return lift(new OperatorMap<T, R>(func));
}
public final class OperatorMap<T, R> implements Operator<R, T> {
private final Func1<? super T, ? extends R> transformer;
public OperatorMap(Func1<? super T, ? extends R> transformer) {
this.transformer = transformer;
}
@Override
public Subscriber<? super T> call(final Subscriber<? super R> o) {
return new Subscriber<T>(o) {
@Override
public void onCompleted() {
o.onCompleted();
}
@Override
public void onError(Throwable e) {
o.onError(e);
}
@Override
public void onNext(T t) {
try {
o.onNext(transformer.call(t));
} catch (Throwable e) {
Exceptions.throwOrReport(e, this, t);
}
}
};
}
}
看到OperatorMap.call()
方法,它直接生成一個新的Subscriber
,通過上面的分析可以知道,這是一個代理Subscriber,所以它的onNext()
等方法都只是直接調用了外部傳進來的Subscriber
。
舉個例子:
Observable.just(1.34f, 8.3453f, -534.34f, 392.99f)
.map(new Func1<Float, Integer>() {
@Override
public Integer call(Float aFloat) {
return Math.round(aFloat);
}
})
.map(new Func1<Integer, String>() {
@Override
public String call(Integer integer) {
return Integer.toBinaryString(integer);
}
})
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
log("2 map onNext->" + s);
}
});
// outputs
// 2 map onNext->1
// 2 map onNext->1000
// 2 map onNext->11111111111111111111110111101010
// 2 map onNext->110001001
該例子是一個Float->Integer->String
的轉換。我們按上面的流程來分析。
1、生成一個Observable<Float>
。
2、調用map()
生成一個Observable<Integer>
。
3、再調用map()
生成一個Observable<String>
。
4、subscribe()
一個Subscriber<String>
。至此流的前半部分完成。
5、執(zhí)行開始,Observable<String>
發(fā)送事件,先生成一個Subscriber<Integer>
傳給Observable<Integer>
(Observable<Integer>.onSubscribe.call()
)。
6、Observable<Integer>
開始發(fā)送事件,同樣的生成一個Subscriber<Float>
傳給Observable<Float>
(Observable<Float>.onSubscribe.call()
)。
7、真正發(fā)送事件開始,Observable<Float>
調用Subscriber<Float>.onNext(Float)
等方法,同時Subscriber<Integer>.onNext(Integer)
被調用,同時Subscriber<String>.onNext(String)
被調用,事件發(fā)送完成。
8、雖然是流的模型,但其實是一堆內部類和外部類的嵌套關系。