運(yùn)用RxJava(三)Reactive的優(yōu)點(diǎn)

原文鏈接,翻譯:葛藤灣


第一部分,我介紹了RxJava的基本結(jié)構(gòu);在第二部分我講述了RxJava強(qiáng)大的操作符。但也許你還是沒有被說服,這里將介紹RxJava框架的其他優(yōu)點(diǎn),它們應(yīng)該能夠說服你。

錯誤處理

一直到現(xiàn)在,我們都忽略了onComplete()和onError(),它們標(biāo)記著一個Observable停止發(fā)送數(shù)據(jù)的時間和原因(不論是成功完成還是不可恢復(fù)的錯誤)。

我們初始的Subscriber有監(jiān)聽onComplete()和onError()的能力。讓我們用這兩個方法來做點(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!"); }
    });

我們說potentialException()和anotherPotentialException()都有拋出異常的可能,每個Observable都以調(diào)用一次onComplete()或者onError()結(jié)束。就這樣,程序的輸出要么是一個String后接“Completed!”,要么就是“Ouch!”(因?yàn)橛挟惓伋觯?/p>

從這個模式中我們可以得出幾個結(jié)論:

1. 任何時候,如果有異常被拋出,onError()就會被調(diào)用。

這使得錯誤處理變得極為簡單,我能夠只在一個方法的最后處理每個錯誤。

2. 操作符并不一定要處理錯誤。

你能夠一直到Subscriber中才決定怎么處理Observable鏈中任意一部分的錯誤,因?yàn)楫惓給nError()。

3. 你可以知道Subscriber結(jié)束接收數(shù)據(jù)的時間。

知道一個任務(wù)的結(jié)束時間可以幫助你整理代碼流(盡管有可能一個Observable永遠(yuǎn)不會執(zhí)行結(jié)束)。

我發(fā)現(xiàn)這個模式比傳統(tǒng)的錯誤處理要簡便得多。采用回調(diào),你必須在每一個回調(diào)中都進(jìn)行錯誤處理,這不僅會導(dǎo)致繁復(fù)的代碼,而且意味著每一個回調(diào)都必須知道如何處理錯誤,也意味著你的回調(diào)和它的調(diào)用者是緊耦合的。

然而采用RxJava的這種模式,你的Observable甚至不需要知道如何處理錯誤。所有的操作符也不需要處理錯誤狀態(tài)——在發(fā)送關(guān)鍵錯誤的情況下它會被跳過。你可以將你所有的錯誤處理都放到Subscriber中。

調(diào)度器

假設(shè)你有一個Android APP需要進(jìn)行網(wǎng)絡(luò)請求,這可能會耗費(fèi)很長時間,所以你需要新開線程來處理它,突然,這就遇到了問題。

多線程的Android應(yīng)用是很麻煩的,因?yàn)槟惚仨毐WC你的代碼運(yùn)行在正確的線程中,如果錯了,你的應(yīng)用就會crash。典型的異常發(fā)生在非主線程中修改View的狀態(tài)。

使用RxJava,你可以使用subscribeOn()指定你的Observer代碼運(yùn)行的線程,也可以使用observeOn()指定你的Subscriber運(yùn)行在哪個線程:

myObservableServices.retrieveImage(url)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(bitmap -> myImageView.setImageBitmap(bitmap));

很簡單吧?Subscriber之前的所有代碼都運(yùn)行在IO線程中,最后,我的View操作發(fā)生在主線程。

這里的卓越之處在于我能給任意的Observable添加subscribeOn()和observeOn()。它們只是操作符!我不需要擔(dān)心Observable或者之前的操作符正在做什么;我只需要在最后加上這些就可以方便地進(jìn)行多線程編程。

Subscriptions

其實(shí)我還有一些事情隱瞞了你。當(dāng)你調(diào)用Observable.subscribe()的時候,返回的是一個Subscription。它代表著你的Observable和你的Subscriber之間的聯(lián)系:

Subscription subscription = Observable.just("Hello, World!")
    .subscribe(s -> System.out.println(s));

你隨后也可以使用Subscription來切斷這種聯(lián)系:

subscription.unsubscribe();
System.out.println("Unsubscribed=" + subscription.isUnsubscribed());
// Outputs "Unsubscribed=true"

RxJava取消訂閱的好處是它切斷了整個鏈?zhǔn)秸{(diào)用。如果你有一個復(fù)雜的操作鏈,使用unsubscribe()你可以在代碼運(yùn)行到的任何地方終止,卻不需要任何其他工作。

結(jié)論

記住,這個系列文章只是RxJava的一個簡介,除了我說的這些外還有太多值得去學(xué),并且不會是一帆風(fēng)順的(比如,讀讀這篇文章)。我也不是所有的代碼都使用Reactive的——我將它留到我想要簡化邏輯的程序的復(fù)雜部分。

一開始,我是計(jì)劃將這篇文章作為這個系列的結(jié)束的,后來很多人要求給出一個在Android上使用RxJava的練習(xí)demo,所以你現(xiàn)在可以繼續(xù)閱讀第四部分(需要科學(xué)上網(wǎng))。我希望這個介紹足以讓你開始動手編程了,如果你想了解更多的話,我建議你閱讀RxJava官方wiki,并且記住,一切皆有可能。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容