從案例學RxAndroid開發(上)

原文連接:RxAndroid Basics: Part 1java

若是你在閱讀這篇文章,相信你必定很想了解RxJava以及如何在Android應用中使用它。可能你已經見過RxJava的代碼了,但仍然有些疑惑,願你能在這篇文章裏找到答案。android

當我第一次使用RxJava的時候我只是在照搬代碼,這些代碼能跑起來,可是我對RxJava的基礎部分仍然存在誤解,並且我找不到好的源碼來學習。因此爲了理解RxJava,我不得不一點一點學習,踩了很多坑。git

爲了避免讓你把我踩過的坑再踩一遍,我會基於個人學習成果寫一些例子出來,目的就是讓你可以對RxJava有足夠的瞭解,並能在你的Android應用中使用它。github

源碼能夠在這裏找到。在每一個例子的開始,我會寫清每一個代碼段是屬於哪一個Activity的。我會將本文分爲兩個部分,在第一部分裏,我會着重講解如何用RxJava異步加載數據;在第二部分裏,我會探索一些更高級的用法。網絡

幾個概念

在開始說代碼以前,先澄清幾個概念。RxJava最核心的東西就是Observable和Observer。Observable會發出數據,而與之相對的Observer則會經過訂閱Observable來進行觀察。多線程

Observer能夠在Observable發出數據、報錯或者聲明沒有數據能夠發送時進行相應的操做。這三個操做被封裝在Observer接口中,相應的方法爲onNext(),onError()和onCompleted()。app

明確了這些概念之後,讓咱們來看一些例子。異步

案例1:基礎

如今要寫一個用來展現一個顏色列表的Activity。咱們要寫一個能發送一個字符串列表、而後結束的Observeable。然後咱們會經過這個字符串列表來填充顏色列表,這裏要使用到Observable.just()方法。由這個方法建立的Observable對象的特色是:全部Observer一旦訂閱這個Observable就會當即調用onNext()方法並傳入Observable.just()的參數,然後由於Observable沒有數據能夠發送了,onComplete()方法會被調用。ide

Observable<List<String>> listObservable = Observable.just(getColorList());

注意這裏的getColorList()是一個不耗時的方法。雖然如今看來這個方法無足輕重,但一會咱們會回到這個方法。學習

下一步,咱們寫一個Observer來觀察Observable。

listObservable.subscribe(new Observer<List<String>>() { 

    @Override 
    public void onCompleted() { } 

    @Override 
    public void onError(Throwable e) { } 

    @Override
    public void onNext(List<String> colors) {
        mSimpleStringAdapter.setStrings(colors);
    }
});

然後神奇的事情就發生了。如我剛纔所說,一旦經過subscribe()方法訂閱Observable,就會發生一系列事情:

  1. onNext()方法被調用,被髮送的顏色列表會做爲參數傳入。
  2. 既然再也不有數據能夠發送(咱們在Observable.just()中只讓Observable發送一個數據),onComplete()方法會被調用。

請記住:經過Observable被訂閱後的行爲來區分它們

在這個例子中咱們不關心Observable什麼時候完成數據的傳輸,因此咱們不用在onComplete()方法裏寫代碼。並且在這裏不會有異常拋出,因此咱們也不用管onError()方法。

寫了這麼多你可能以爲不少餘,畢竟咱們本能夠在adapter中直接設置做爲數據源的顏色列表。請帶着這個疑問,和我看下面這個更有趣一些的例子。

案例2:異步加載

在這裏咱們要寫一個顯示電視劇列表的Activity。在Android中RxJava的主要用途就在於異步數據加載。首先讓咱們寫一個Observable:

Observable<List<String>> tvShowObservable = Observable.fromCallable(new Callable<List<String>>() { 

    @Override 
    public List<String> call() { 
        return mRestClient.getFavoriteTvShows(); 
    }
});

在剛纔的例子中,咱們使用Observable.just()來建立Observable,你可能認爲在這裏能夠經過Observable.just(mRestClient.getFavoriteTvShows())來建立Observable。

但在這裏咱們不能這麼作,由於mRestClient.getFavoriteTvShows()會發起網絡請求。若是在這裏咱們使用Observable.just(),mRestClient.getFavoriteTvShows()會被當即執行並阻塞UI線程。

使用Observable.fromCallable()方法有兩點好處:

  1. 獲取要發送的數據的代碼只會在有Observer訂閱以後執行。
  2. 獲取數據的代碼能夠在子線程中執行。

這兩點好處有時可能很是重要。如今讓咱們訂閱這個Observable。

mTvShowSubscription = tvShowObservable
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Observer<List<String>>() {

        @Override 
        public void onCompleted() { }

        @Override 
        public void onError(Throwable e) { }

        @Override 
        public void onNext(List<String> tvShows){
            displayTvShows(tvShows);
        }
    });

讓咱們一個方法一個方法地來看這段代碼。subscribeOn會修改咱們剛剛建立的Observable。在默認狀況下Observable的全部代碼,包括剛纔說到的只有在被訂閱以後纔會執行的代碼,都會在執行subscribe()方法的線程中運行。而經過subscribeOn()方法,這些代碼能夠在其餘線程中執行。但具體是哪一個線程呢?

在這個例子中咱們讓代碼在"IO Scheduler"中執行(Schedulers.io())。如今咱們能夠只把Scheduler當作一個能夠工做的子線程,這個描述對於如今的咱們已經足夠了,不過這其中還有更深層次的內容。

不過咱們的確遇到了一個小障礙。既然Observable會在IO Scheduler中運行,那麼它與Observer的鏈接也會在IO Scheduler中完成。這就意味着Observer的onNext()方法也會在IO Scheduler中運行,而onNext()方法會操做UI中的View,但View只能在UI主線程中操做。

事實上解決這個問題也很簡單,咱們能夠告訴RxJava咱們要在UI線程中觀察這個Observable,也就是,咱們想讓onNext()方法在UI線程中執行。這一點咱們能夠經過在observeOn()方法中指定另外一個Scheduler來完成,在這裏也就是AndroidSchedules.mainThread()所返回的Scheduler(UI線程的Scheduler)。

然後咱們調用subscribe()方法。這個方法最重要,由於Callable只會在有Observer訂閱後運行。還記得剛纔我說Observable經過其被訂閱後的行爲來區分嗎?這就是一個很好的例子。

還有最後一件事。這個mTvShowSubscription究竟是什麼?每當Observer訂閱Observable時就會生成一個Subscription對象。一個Subscription表明了一個Observer與Observable之間的鏈接。有時咱們須要操做這個鏈接,這裏拿在Activity的onDestroy()方法中的代碼舉個例子:

if (mTvShowSubscription != null && !mTvShowSubscription.isUnsubscribed()) {
    mTvShowSubscription.unsubscribe();
}

若是你與多線程打過交道,你確定會意識到一個大坑:當Activity執行onDestroy()後線程才結束(甚至永不結束)的話,就有可能發生內存泄漏與NullPointerException空指針異常。

Subscription就能夠解決這個問題,咱們能夠經過調用unsubscribe()方法告訴Observable它所發送的數據再也不被Observer所接收。在調用unsubscribe()方法後,咱們建立的Observer就再也不會收到數據了,同時也就解決了剛纔說的問題。

說到這裏難點已通過去,讓咱們來總結一下:

  • Observable.fromCallable()方法能夠拖延Observable獲取數據的操做,這一點在數據須要在其餘線程獲取時尤爲重要。
  • subscribeOn()讓咱們在指定線程中運行獲取數據的代碼,只要不是UI線程就行。
  • observeOn()讓咱們在合適的線程中接收Observable發送的數據,在這裏是UI主線程。
  • 記住要讓Observer取消訂閱以避免Observable異步加載數據時發生意外。

案例3:使用Single

此次咱們仍是寫一個展現電視劇列表的Activity,但此次咱們走一種更簡單的風格。Observable挺好用的,但在某些狀況下過於重量級。好比說,你可能一經發如今過去的兩個方法中咱們只是讓Observable發送一個數據,並且咱們歷來也沒寫過onComplete()回調方法。

其實呢,Observable還有一個精簡版,叫作Single。Single幾乎和Observable如出一轍,但其回調方法不是onComplete()/onNext()/onError(),而是onSuccess()/onError()。

咱們如今把剛纔寫過的Observable用Single重寫一遍。首先咱們要建立一個Single:

Single<List<String>> tvShowSingle = Single.fromCallable(new Callable<List<String>>() { 
    @Override
    public List<String> call() throws Exception {
        mRestClient.getFavoriteTvShows(); 
    }
});

而後訂閱一下:

mTvShowSubscription = tvShowSingle
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new SingleSubscriber<List<String>>() {

        @Override 
        public void onSuccess(List<String> tvShows) {
            displayTvShows(tvShows); 
        }

        @Override 
        public void onError(Throwable error) {
            displayErrorMessage(); 
        } 
    });

這段代碼和剛纔很像,咱們調用subscribeOn()方法以確保getFavoriteTvShows()在子線程中執行。然後咱們調用observeOn()以確保Single的數據被髮送到UI線程。

但此次咱們再也不使用Observer,而是使用一個叫SingleSubscriber的類。這個類和Observer很是像,只不過它只有上述兩個方法:onSuccess()和onError()。SingleSubscriber之於Single就如Observer之於Observable。

訂閱一個Single的同時也會自動建立一個Subscription對象。這裏的Subscription和案例2中沒有區別,必定要在onDestroy()中解除訂閱。

最後一點:在這裏咱們添加了處理異常的代碼,因此若是mRestClient出了問題,onError()就會被調用。建議你親手寫一個案例玩一玩,體驗一下有異常時程序是怎麼運行的。

相關文章
相關標籤/搜索