在第一部分烛愧,我介紹了RxJava的基本結(jié)構(gòu);在第二部分我講述了RxJava強(qiáng)大的操作符希痴。但也許你還是沒(méi)有被說(shuō)服者甲,這里將介紹RxJava框架的其他優(yōu)點(diǎn),它們應(yīng)該能夠說(shuō)服你砌创。
錯(cuò)誤處理
一直到現(xiàn)在虏缸,我們都忽略了onComplete()和onError()甥厦,它們標(biāo)記著一個(gè)Observable停止發(fā)送數(shù)據(jù)的時(shí)間和原因(不論是成功完成還是不可恢復(fù)的錯(cuò)誤)。
我們初始的Subscriber有監(jiān)聽(tīng)onComplete()和onError()的能力寇钉。讓我們用這兩個(gè)方法來(lái)做點(diǎn)實(shí)際的事吧:
Observable.just("Hello, world!")
.map(s -> potentialException(s))
.map(s -> anotherPotentialException(s))
.subscribe(new Subscriber<String>() {
@Override
public void onNext(String s) { System.out.println(s); }
@Override
public void onCompleted() { System.out.println("Completed!"); }
@Override
public void onError(Throwable e) { System.out.println("Ouch!"); }
});
我們說(shuō)potentialException()和anotherPotentialException()都有拋出異常的可能刀疙,每個(gè)Observable都以調(diào)用一次onComplete()或者onError()結(jié)束。就這樣扫倡,程序的輸出要么是一個(gè)String后接“Completed!”谦秧,要么就是“Ouch!”(因?yàn)橛挟惓伋觯?/p>
從這個(gè)模式中我們可以得出幾個(gè)結(jié)論:
1. 任何時(shí)候,如果有異常被拋出撵溃,onError()就會(huì)被調(diào)用疚鲤。
這使得錯(cuò)誤處理變得極為簡(jiǎn)單,我能夠只在一個(gè)方法的最后處理每個(gè)錯(cuò)誤缘挑。
2. 操作符并不一定要處理錯(cuò)誤集歇。
你能夠一直到Subscriber中才決定怎么處理Observable鏈中任意一部分的錯(cuò)誤,因?yàn)楫惓?huì)跳到onError()语淘。
3. 你可以知道Subscriber結(jié)束接收數(shù)據(jù)的時(shí)間诲宇。
知道一個(gè)任務(wù)的結(jié)束時(shí)間可以幫助你整理代碼流(盡管有可能一個(gè)Observable永遠(yuǎn)不會(huì)執(zhí)行結(jié)束)。
我發(fā)現(xiàn)這個(gè)模式比傳統(tǒng)的錯(cuò)誤處理要簡(jiǎn)便得多惶翻。采用回調(diào)姑蓝,你必須在每一個(gè)回調(diào)中都進(jìn)行錯(cuò)誤處理,這不僅會(huì)導(dǎo)致繁復(fù)的代碼吕粗,而且意味著每一個(gè)回調(diào)都必須知道如何處理錯(cuò)誤纺荧,也意味著你的回調(diào)和它的調(diào)用者是緊耦合的。
然而采用RxJava的這種模式颅筋,你的Observable甚至不需要知道如何處理錯(cuò)誤宙暇。所有的操作符也不需要處理錯(cuò)誤狀態(tài)——在發(fā)送關(guān)鍵錯(cuò)誤的情況下它會(huì)被跳過(guò)。你可以將你所有的錯(cuò)誤處理都放到Subscriber中议泵。
調(diào)度器
假設(shè)你有一個(gè)Android APP需要進(jìn)行網(wǎng)絡(luò)請(qǐng)求占贫,這可能會(huì)耗費(fèi)很長(zhǎng)時(shí)間,所以你需要新開(kāi)線(xiàn)程來(lái)處理它肢簿,突然靶剑,這就遇到了問(wèn)題。
多線(xiàn)程的Android應(yīng)用是很麻煩的池充,因?yàn)槟惚仨毐WC你的代碼運(yùn)行在正確的線(xiàn)程中桩引,如果錯(cuò)了,你的應(yīng)用就會(huì)crash收夸。典型的異常發(fā)生在非主線(xiàn)程中修改View的狀態(tài)坑匠。
使用RxJava,你可以使用subscribeOn()指定你的Observer代碼運(yùn)行的線(xiàn)程卧惜,也可以使用observeOn()指定你的Subscriber運(yùn)行在哪個(gè)線(xiàn)程:
myObservableServices.retrieveImage(url)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(bitmap -> myImageView.setImageBitmap(bitmap));
很簡(jiǎn)單吧厘灼?Subscriber之前的所有代碼都運(yùn)行在IO線(xiàn)程中夹纫,最后,我的View操作發(fā)生在主線(xiàn)程设凹。
這里的卓越之處在于我能給任意的Observable添加subscribeOn()和observeOn()舰讹。它們只是操作符!我不需要擔(dān)心Observable或者之前的操作符正在做什么闪朱;我只需要在最后加上這些就可以方便地進(jìn)行多線(xiàn)程編程月匣。
Subscriptions
其實(shí)我還有一些事情隱瞞了你。當(dāng)你調(diào)用Observable.subscribe()的時(shí)候奋姿,返回的是一個(gè)Subscription锄开。它代表著你的Observable和你的Subscriber之間的聯(lián)系:
Subscription subscription = Observable.just("Hello, World!")
.subscribe(s -> System.out.println(s));
你隨后也可以使用Subscription來(lái)切斷這種聯(lián)系:
subscription.unsubscribe();
System.out.println("Unsubscribed=" + subscription.isUnsubscribed());
// Outputs "Unsubscribed=true"
RxJava取消訂閱的好處是它切斷了整個(gè)鏈?zhǔn)秸{(diào)用。如果你有一個(gè)復(fù)雜的操作鏈称诗,使用unsubscribe()你可以在代碼運(yùn)行到的任何地方終止萍悴,卻不需要任何其他工作。
結(jié)論
記住寓免,這個(gè)系列文章只是RxJava的一個(gè)簡(jiǎn)介癣诱,除了我說(shuō)的這些外還有太多值得去學(xué),并且不會(huì)是一帆風(fēng)順的(比如再榄,讀讀這篇文章)狡刘。我也不是所有的代碼都使用Reactive的——我將它留到我想要簡(jiǎn)化邏輯的程序的復(fù)雜部分享潜。
一開(kāi)始困鸥,我是計(jì)劃將這篇文章作為這個(gè)系列的結(jié)束的,后來(lái)很多人要求給出一個(gè)在Android上使用RxJava的練習(xí)demo剑按,所以你現(xiàn)在可以繼續(xù)閱讀第四部分(需要科學(xué)上網(wǎng))疾就。我希望這個(gè)介紹足以讓你開(kāi)始動(dòng)手編程了,如果你想了解更多的話(huà)艺蝴,我建議你閱讀RxJava官方wiki猬腰,并且記住,一切皆有可能猜敢。