lift()
方法是RxJava中所有操作符的基礎(chǔ)鹃骂,可以通過(guò)它做各種各樣的變化。弄清楚它的原理,也方便我們理解其他操作符园骆。首先先看幾個(gè)相關(guān)接口。
Func1 接口
public interface Func1<T, R> extends Function {
R call(T t);
}
Func1
接口會(huì)按照泛型參數(shù)的順序傳入T
寓调,并返回R
锌唾。
Operator 接口
public interface Operator<R, T> extends Func1<Subscriber<? super R>, Subscriber<? super T>>
按照Func1
接口的定義,Operator
接口會(huì)傳入一個(gè)Subscriber<? super R>
參數(shù)夺英,并返回一個(gè)Subscriber<? super T>
晌涕。
關(guān)于Operator和lift()中泛型順序的問(wèn)題
也許有人(is me)第一眼看到Observable<T>
,Operator<R, T>
痛悯,Func1<T, R>
這幾個(gè)類(lèi)的泛型參數(shù)余黎,頭都大了,關(guān)鍵是Operator
的泛型參數(shù)順序?yàn)槭裁词?code>R, T载萌,而不是T, R
惧财?
其實(shí)這里不需要關(guān)心順序是什么,只需要記住Operator<R, T>
是按照泛型參數(shù)的順序炒考,傳入一個(gè)Subscriber<R>
參數(shù)可缚,并返回一個(gè)Subscriber<T>
,寫(xiě)成Operator<A, B>
或者Operator<M, N>
是沒(méi)有任何區(qū)別的斋枢。
lift()調(diào)用流程
首先需要記住lift()
方法是在一個(gè)已有Observable
上調(diào)用的帘靡。
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是調(diào)用lift方法的Observable中的onSubscribe
onSubscribe.call(st);
}
});
}
根據(jù)代碼的調(diào)用流程來(lái)分析:
1、假設(shè)已有一個(gè)Observable<T>
瓤帚,調(diào)用lift()
方法描姚,生成一個(gè)Observable<R>
,此時(shí)就有了兩個(gè)Observable
和兩個(gè)OnSubscribe
對(duì)象戈次。
2轩勘、然后調(diào)用Observable<R>
的subscribe()
方法,傳入一個(gè)Subscriber<R>
對(duì)象怯邪,此時(shí)觸發(fā)Observable<R>.onSubscribe.call()
方法绊寻,也就是上面lift()
方法中的call()
方法。
3悬秉、在該方法中會(huì)調(diào)用onSubscribe.call()
方法澄步,注意這個(gè)onSubscribe
是Observable<T>
中的那個(gè)OnSubscribe<T>
對(duì)象,它需要傳入一個(gè)Subscriber<T>
對(duì)象和泌,這個(gè)對(duì)象是通過(guò)operator.call()
方法生成的村缸。正是這個(gè)Operator
對(duì)象將兩個(gè)Subscriber
對(duì)象關(guān)聯(lián)起來(lái),OnSubscribe<T>
在執(zhí)行Subscriber<T>.onNext(T t)
方法的時(shí)候也會(huì)執(zhí)行Subscriber<R>.onNext(R r)
武氓,而這里從T
變成R
梯皿,正好用到了傳到Operator
中的參數(shù)Func1<T, R>
仇箱。
4、如果具體化一點(diǎn)东羹,上面的Observable<T>
就是事件源剂桥,對(duì)它進(jìn)行lift()
變換得到新的Observable<R>
,這個(gè)新的Observable
的回調(diào)已經(jīng)固定百姓,相當(dāng)于是一個(gè)模板(也就是上面lift()
方法中的call()
方法)渊额。這時(shí)調(diào)用subscribe()
况木,傳入的Subscriber<R>
是用戶(hù)定義的事件監(jiān)聽(tīng)者垒拢,但它監(jiān)聽(tīng)的是新的Observable<R>
,這個(gè)Observable
的回調(diào)是固定的火惊,它并不能產(chǎn)生新事件求类,所以得靠事件源Observable<T>
。這個(gè)時(shí)候Operator
生成一個(gè)中間的Subscriber<T>
對(duì)象屹耐,該對(duì)象的作用就是接收事件源的事件尸疆,并將事件轉(zhuǎn)給用戶(hù)定義的Subscriber
。這個(gè)Subscriber<T>
并沒(méi)有消耗事件惶岭,而是起著一個(gè)代理的作用寿弱。所以Operator
可以看做是一個(gè)生成代理的工具類(lèi)。在這個(gè)轉(zhuǎn)發(fā)過(guò)程中有一個(gè)數(shù)據(jù)類(lèi)型的變化過(guò)程按灶,也是通過(guò)Operator
的轉(zhuǎn)換器Func1實(shí)現(xiàn)的症革,想怎樣轉(zhuǎn)換數(shù)據(jù),也是用戶(hù)定義后傳到Operator
中的鸯旁。
小結(jié)
1噪矛、我們需要把Observable
的調(diào)用看做一條流。
2铺罢、對(duì)于Observable<T> -> Observable<R>
這個(gè)變化艇挨,訂閱者為Subscriber<R>
,在subscriber()
方法調(diào)用后韭赘,流的順序?yàn)?strong>倒序的,即從Observable<R> -> Observable<T>
,因?yàn)槲覀兪冀K需要調(diào)用最開(kāi)始的事件源。為了滿(mǎn)足這個(gè)需求,會(huì)通過(guò)Operator<R, T>
這個(gè)代理工具生成一個(gè)代理Subscriber<T>
,這也解釋了為什么在聲明Operator
時(shí)泛型參數(shù)的順序?qū)憺?code>R, T,正好可以和這一變化對(duì)應(yīng)起來(lái)铺峭,用相同的泛型參數(shù)更便于理解虱朵。這樣準(zhǔn)備工作就都做好了。
3、Observable<T>
開(kāi)始向Subscriber<T>
發(fā)送事件,發(fā)送的參數(shù)類(lèi)型為T
,這時(shí)候通過(guò)轉(zhuǎn)換器Func1
將T
變成R
铣揉,這樣就能順利的通過(guò)代理Subscriber<T>
將事件發(fā)送給Subscriber<R>
了朽合。
4休讳、所以流的路線(xiàn)為Observable<R> -> Observable<T> -> Subscriber<T> -> Subscriber<R>
俊柔。一條線(xiàn)分成兩部分,前半部分為準(zhǔn)備工作活合,后半部分為執(zhí)行操作雏婶。
下圖是lift()
的過(guò)程,其中虛線(xiàn)箭頭代表生成芜辕,實(shí)線(xiàn)箭頭代表調(diào)用尚骄。也可以參考 扔物線(xiàn) - 給 Android 開(kāi)發(fā)者的 RxJava 詳解 中的配圖。
map()方法
map()
方法是RxJava中使用lift()
最簡(jiǎn)單的方法侵续,如果上面lift()
方法過(guò)于抽象,可以通過(guò)該方法來(lái)加深理解憨闰。
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()
方法状蜗,它直接生成一個(gè)新的Subscriber
,通過(guò)上面的分析可以知道鹉动,這是一個(gè)代理Subscriber轧坎,所以它的onNext()
等方法都只是直接調(diào)用了外部傳進(jìn)來(lái)的Subscriber
。
舉個(gè)例子:
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
該例子是一個(gè)Float->Integer->String
的轉(zhuǎn)換泽示。我們按上面的流程來(lái)分析缸血。
1、生成一個(gè)Observable<Float>
械筛。
2捎泻、調(diào)用map()
生成一個(gè)Observable<Integer>
。
3埋哟、再調(diào)用map()
生成一個(gè)Observable<String>
笆豁。
4、subscribe()
一個(gè)Subscriber<String>
赤赊。至此流的前半部分完成闯狱。
5、執(zhí)行開(kāi)始抛计,Observable<String>
發(fā)送事件哄孤,先生成一個(gè)Subscriber<Integer>
傳給Observable<Integer>
(Observable<Integer>.onSubscribe.call()
)。
6吹截、Observable<Integer>
開(kāi)始發(fā)送事件瘦陈,同樣的生成一個(gè)Subscriber<Float>
傳給Observable<Float>
(Observable<Float>.onSubscribe.call()
)朦肘。
7、真正發(fā)送事件開(kāi)始双饥,Observable<Float>
調(diào)用Subscriber<Float>.onNext(Float)
等方法媒抠,同時(shí)Subscriber<Integer>.onNext(Integer)
被調(diào)用,同時(shí)Subscriber<String>.onNext(String)
被調(diào)用咏花,事件發(fā)送完成趴生。
8、雖然是流的模型昏翰,但其實(shí)是一堆內(nèi)部類(lèi)和外部類(lèi)的嵌套關(guān)系苍匆。