鍍金池/ 教程/ Android/ RxAndroid 基礎(chǔ):第一部分
101 種讓你的網(wǎng)頁看起來更酷的方法
Android 項(xiàng)目是如何使用 Kotlin 語言生成的 1/2
Nimbledroid 版本更新
使用TypeScript提高開發(fā)能力
利用 TensorFlow Serving 系統(tǒng)在生產(chǎn)環(huán)境中運(yùn)行模型
Google Play 榜單APP冷啟動(dòng)速度分析報(bào)告
使用微信控制電腦(Python 版)
jQuery 3 中的新變動(dòng)
RxAndroid 基礎(chǔ):第一部分
Swift in 2016
UI自動(dòng)化測(cè)試基于Activity的封裝模式
2016年,有哪些適合你學(xué)習(xí)的編程語言?
Swift 響應(yīng)式編程
如何組合使用 VIM 編輯器與 IPYthon
如何使你的app更加流暢
介紹用來選擇輪廓圖像的一個(gè)類——Will J Miller
關(guān)于Android N 開發(fā)者預(yù)覽版的一些隨想

RxAndroid 基礎(chǔ):第一部分

譯者:李鑫

原文:RxAndroid Basics: Part 1

本文為極客學(xué)院Wiki組織翻譯,轉(zhuǎn)載請(qǐng)注明出處。

時(shí)間:2016.3.8

歡迎!你可能對(duì) RxJava 的這個(gè)擴(kuò)展以及它在 Android 上的應(yīng)用感到有些好奇?;蛟S你已經(jīng)見識(shí)過它的一些用途,但可能感覺有些疑問,想要一些詳細(xì)的介紹,那么本文肯定能解決你的疑問。

當(dāng)我第一次接觸 RxJava 時(shí),多數(shù)都是采用貨物崇拜式編程的方式。有時(shí)是奏效的,但我對(duì)一些基礎(chǔ)概念缺乏正確認(rèn)識(shí)。缺乏優(yōu)秀的范例來告訴我到底是怎么回事,所以讓我感到非常失望。為了能夠真正、完整地了解 RxJava,我進(jìn)行了很多探索,其中包含了大量的試錯(cuò)過程。

為了避免親愛的讀者你繼續(xù)彷徨,我決定把自己的探索成果用一些例子展示出來。希望它們能幫助你正確使用 RxJava 開發(fā) Android 應(yīng)用。

這些例子是一個(gè)全功能范例應(yīng)用中的一部分。在每個(gè)例子的開端,將給出范例代碼所在的 Activity 的鏈接。這些例子分成兩部分。在第一部分中,集中解決如何使用 RxJava 異步加載數(shù)據(jù)的問題;第二部分介紹更多高級(jí)的使用模式。

一些必要的概念

在我們開始正式介紹之前,先來介紹一些基本概念。RxJava 其核心是兩種對(duì)象:Observable 對(duì)象及 Observer 對(duì)象。Observable 對(duì)象用來“發(fā)射”值,而 Observer 對(duì)象則通過“訂閱” Observable 對(duì)象來觀察這些對(duì)象。

當(dāng) Observable 對(duì)象發(fā)射值,或者當(dāng) Observable 對(duì)象說明已經(jīng)發(fā)生錯(cuò)誤,或當(dāng) Observable 對(duì)象通知沒有要發(fā)射的值時(shí),Observer 對(duì)象就會(huì)采取相應(yīng)操作。三種操作都被封裝在 Observer 接口內(nèi)。相應(yīng)的函數(shù)為onNext()、onError()onCompleted()

知道了這些,先讓我們來看一些例子。

范例 1:基本范例

先讓我們用一個(gè) Activity 對(duì)象簡單地顯示一列顏色。我們將制作一個(gè) Observable 對(duì)象,讓它先發(fā)射單個(gè)值,再發(fā)射一列字符串,然后結(jié)束。我們將使用 Observable.just() 方法,該方法將創(chuàng)建一個(gè) Observable 對(duì)象,以便當(dāng)一個(gè) Observer 對(duì)象訂閱它時(shí),Observer 的 onNext() 方法會(huì)被立刻調(diào)用,并使用提供給 Observable.just() 的參數(shù)。然后調(diào)用 onComplete(),因?yàn)?Observable 沒有其他值可發(fā)射。

注意,getColorList() 是一個(gè)非阻塞式的方法調(diào)用。這一點(diǎn)現(xiàn)在可能不太重要,但稍后會(huì)繼續(xù)講到它。

下面,建立一個(gè)觀察 Observable 對(duì)象的 Observer 對(duì)象:

這里有些玄機(jī)。如上文所述,一旦利用 subscribe() 方法訂閱了 Observable 對(duì)象,下列步驟將依次發(fā)生:

  1. onNext() 方法被調(diào)用,釋放的顏色列表被設(shè)置為適配器數(shù)據(jù)。
  2. 因?yàn)闆]有其他數(shù)據(jù)(利用 Observable.just(),只讓 Observable 對(duì)象發(fā)射一個(gè)單個(gè)值 ),調(diào)用了onComplete()。

在考慮訂閱時(shí),多思考一下 Observable 對(duì)象是有好處的。實(shí)際上,Observable 對(duì)象就是按照訂閱行為定義的。一定要記住這一點(diǎn),因?yàn)檫@個(gè)概念將來會(huì)很有用。將來會(huì)再次討論它。

Observable 對(duì)象就是根據(jù)訂閱行為定義的。

在本例中,我們完全不用考慮當(dāng) Observable 完成后發(fā)生的事情,所以將 onComplete() 方法保持為空。另外,也不可能拋出錯(cuò)誤,所以將 onError() 也保持為空。

所有這些做法可能看上去有些不必要。將顏色列表直接設(shè)置在適配器中。但是先讓我們來考慮一些有趣的問題。

范例 2:異步加載

利用一個(gè) Activity 異步加載一個(gè)最喜歡的電視節(jié)目列表。異步加載數(shù)據(jù)可能是 RxJava 在 Android 中最常用的用途了。首先,創(chuàng)建 Observable 對(duì)象。

在上面的例子中,使用 Observable.just() 來創(chuàng)建 Observable 對(duì)象,因此對(duì)于這個(gè)例子,我們完全可以同樣采用類似 Observable.just(mRestClient.getFavoriteTvShows()) 的方式來做。

但我們不能這么做,因?yàn)?mRestClient.getFavoriteTvShows() 是一個(gè)阻塞網(wǎng)絡(luò)調(diào)用。如果還使用 Observable.just(),mRestClient.getFavoriteTvShows() 就會(huì)立刻求解,阻塞 UI 線程

Observable.fromCallable() 方法提示了兩種關(guān)鍵內(nèi)容:

  1. 創(chuàng)建發(fā)射值的代碼直到 Observer 被訂閱才運(yùn)行。
  2. 創(chuàng)建代碼可以在不同線程下運(yùn)行。

兩種屬性一會(huì)兒就派上用場(chǎng),先來訂閱 Observable:

先分開來講解各個(gè)函數(shù)。subscribeOn() 基本上影響的是上面創(chuàng)建的 Observable 對(duì)象。Observable 將正常運(yùn)行的所有代碼,包括針對(duì)訂閱運(yùn)行的代碼,將運(yùn)行在不同的線程上。這意味著我們可調(diào)用的對(duì)象——包括對(duì)getFavoriteTvShows() 的調(diào)用——中的邏輯將在不同的線程上運(yùn)行。但它運(yùn)行在哪個(gè)線程上?

在本例中,規(guī)定代碼運(yùn)行在 “IO 調(diào)度器” (Schedulers.io())。 現(xiàn)在我們只需認(rèn)為調(diào)度器是一個(gè)不同的線程即可。實(shí)際上還得介紹更多的內(nèi)容,但對(duì)于我們的目的而言,這種描述已經(jīng)足夠用了。

但現(xiàn)在還是遇到了一點(diǎn)小問題。因?yàn)?Observable 被設(shè)置運(yùn)行在 IO Scheduler 上,這意味著將在 IO Scheduler 上與 Observer 進(jìn)行交互。這就是一個(gè)問題,因?yàn)?onNext() 方法將在 IO Scheduler 上被調(diào)用。onNext() 中的代碼會(huì)一些視圖中調(diào)用方法。視圖方法只能在 UI 線程上調(diào)用。

解決方法很簡單。只需讓 RxJava 明白,我們希望在 UI 線程上觀測(cè)這個(gè) Observable,比如在 UI 線程上調(diào)用 onNext() 回調(diào)。在 observeOn() 中指定另外一個(gè) scheduler,也就是 AndroidSchedules.mainThread()(UI 線程的調(diào)度器)所返回的調(diào)度器。

最后一點(diǎn)要注意的是調(diào)用 subscribe()。這一點(diǎn)很重要,因?yàn)橹挥挟?dāng)實(shí)際訂閱一些東西時(shí),可回調(diào)對(duì)象中的代碼才會(huì)運(yùn)行。知道了我上文中所說的“Observable 對(duì)象就是根據(jù)訂閱行為定義的”的意思了吧?

這還不是最后要做的。mTvShowSubscription 是什么?當(dāng) Observer 訂閱一個(gè) Observable,就會(huì)創(chuàng)建一個(gè) Subscription。Subscription 表示的是 Observer 與 Observable 之間的連接。有時(shí)我們需要保持這種連接。先來看看 Activity 的 onDestroy() 方法中的一些代碼。

如果之前你曾經(jīng)處理過 Android 的線程,那么肯定知道有這樣一種巨大隱患:如果 Activity 被回收后,線程結(jié)束(或永不結(jié)束)執(zhí)行,會(huì)產(chǎn)生什么問題。這將造成一堆問題,比如內(nèi)存泄露和空指針異常(NullPointerExceptions)等。

訂閱可以幫我們解決這個(gè)問題。這個(gè)過程相當(dāng)于說:“Observable,這個(gè) Observer 不想再接收到你的發(fā)射了,不要和這個(gè)Observer再連接了?!蓖ㄟ^調(diào)用 unsubscribe() 來實(shí)現(xiàn)。調(diào)用完 unsubscribe() 后,之前創(chuàng)建的 Observer 不會(huì)再接收發(fā)射,從而避免了 Activity 被回收后,線程結(jié)束作業(yè)(或根本不結(jié)束)所帶來的一堆問題。

最難的部分已經(jīng)介紹完了,讓我們做一個(gè)小小的總結(jié)。

  • Observable.fromCallable() 目的是延遲創(chuàng)建 Observable 所要發(fā)射的值。這通常適用于需要從 UI 線程中創(chuàng)建 Observable 所要發(fā)射的值時(shí)。
  • subscribeOn() 在特定線程中運(yùn)行值創(chuàng)建代碼,該線程不是 UI 線程。
  • observeOn() 在一個(gè)合適的線程中觀察 Observable 的發(fā)射值,也就是主 UI 線程。
  • 我們必須經(jīng)常讓 Observer 取消訂閱,以防止出現(xiàn)利用 Observable 異步加載時(shí)出現(xiàn)的問題。

范例 3:使用 Single

還是用 Activity 加載一列最喜歡的電視節(jié)目,但是這一次換一種簡單的實(shí)現(xiàn)方式。Observable 是非常不錯(cuò)的,但在很多情況下使用它們是有點(diǎn)過頭了。比如,在上面兩個(gè)例子中,我們只發(fā)射了一個(gè)單值,從來沒用過 onComplete() 回調(diào)。

其實(shí),還有一種簡單的 Observable:Single。Single 和 Observable 差不多。但是跟 Observable 有三種回調(diào) onComplete()onNext()onError() 的情況不同,它只有兩種回調(diào):onSuccess()onError()。

下面用 Single 再做一遍上面的例子,首先創(chuàng)建一個(gè) Single。

然后訂閱它。

這個(gè)過程看起來非常熟悉。調(diào)用 subscribeOn(),確保對(duì) getFavoriteTvShows() 的調(diào)用在 UI 線程外運(yùn)行。調(diào)用 observeOn() 確保在 UI 線程發(fā)射 Single 的結(jié)果。

與其使用 Observer,我們將使用 SingleSubscriber 類。它跟 Observer 非常類似,但只包含上面提到的兩種方法:onSuccess()onError()。SingleSubscriber 對(duì)應(yīng) Single,就像 Observer 對(duì)應(yīng) Observable。

訂閱 Single 同樣也產(chǎn)生了一個(gè) Subscription 對(duì)象。這種訂閱和范例 2 中一樣,同樣也需要用 onDestroy() 取消訂閱。

最后一點(diǎn)。這一范例中還添加了錯(cuò)誤處理代碼。所以,如果 mRestClient 調(diào)用拋出了錯(cuò)誤,就會(huì)獲得 onError 回調(diào)。我建議你實(shí)際編寫并調(diào)試一下這個(gè)例子,看看在不使用 mRestClient.getFavoriteTvShows,而是使用 mRestClient.getFavoriteTvShowsWithException() 時(shí)會(huì)出現(xiàn)什么情況。

最后總結(jié)

這就是第一部分的內(nèi)容了。我希望這些例子能對(duì)你有所幫助。接著看第二部分的介紹吧,這些復(fù)雜的范例會(huì)讓你收獲更多的。

作者簡介

Kurtis Nusbaum 是一位任職于 Uber 的移動(dòng)應(yīng)用開發(fā)者,他非常喜歡長跑。他的社交網(wǎng)站賬號(hào)為: FacebookLinkedIn。哦,還有他的Github 賬號(hào)。如果你覺得 Kurtis 是一位好的合作者,可以通過kcommiter@gmail.com聯(lián)系他。