RxJava 學習筆記(二)

給 Android 開發者的 RxJava 詳解

這篇文章已經寫的很詳細了。但是畢竟是別人的東西 ,既然是學習筆記,我當然要寫寫自己的總結或者摘要,剔除那些不需要的話

https://github.com/ReactiveX/RxJava

https://github.com/ReactiveX/RxAndroid

本人感覺只要掌握了 map 和 flatmap 其實就已經可以算入門了

一.RxJava的觀察者模式

  • 上一篇已經寫了兩個demo 來重溫 傳統觀察者模式 還有Rxjava的配置Rxjava 學習筆記(一)
  • Rxjava 是什麼 –> 異步
  • Rxjava 優點 –> 簡潔,在一條鏈上(鏈式編程),當然最重要的是可以用來裝逼!!!裝逼!裝逼!裝逼!重要的事情說三篇!

  • RxJava 有四個基本概念:Observable (可觀察者,即被觀察者)、 Observer (觀察者)、 subscribe (訂閱)、事件。ObservableObserver 通過 subscribe() 方法實現訂閱關係,從而 Observable 可以在需要的時候發出事件來通知 Observer

RxJava的觀察者模式:

                    onNext(param)
                    onCompleted()
                    onError(error)
Observable ——————> Observer

二.基本實現

  • 步驟:創建Observer(觀察者),創建Observable(被觀察者),Subscribe(訂閱)

1)創建Observer(觀察者)

Observer<String> observer = new Observer<String>() {
    @Override
    public void onNext(String s) {
            Log.d(tag, "Item: " + s);
    }

    @Override
    public void onCompleted() {
        Log.d(tag, "Completed!");
    }

    @Override
    public void onError(Throwable e) {
        Log.d(tag, "Error!");
    } 
};  

除了 Observer 接口之外,RxJava 還內置了一個實現了 Observer 的抽象類:Subscriber。 Subscriber 對 Observer 接口進行了一些擴展,但他們的基本使用方式是完全一樣的:

Subscriber<String> subscriber = new Subscriber<String>() {
    @Override
    public void onNext(String s) {
        Log.d(tag, "Item: " + s);
    }

    @Override
    public void onCompleted() {
        Log.d(tag, "Completed!");
    }

    @Override
    public void onError(Throwable e) {
        Log.d(tag, "Error!");
    }
};

不僅基本使用方式一樣,實質上,在 RxJava 的 subscribe 過程中,Observer 也總是會先被轉換成一個 Subscriber 再使用。所以如果你只想使用基本功能,選擇 Observer 和 Subscriber 是完全一樣的。它們的區別對於使用者來說主要有兩點:

onStart(): 這是 Subscriber 增加的方法。它會在 subscribe 剛開始,而事件還未發送之前被調用,可以用於做一些準備工作,例如數據的清零或重置。這是一個可選方法,默認情況下它的實現爲空。需要注意的是,如果對準備工作的線程有要求(例如彈出一個顯示進度的對話框,這必須在主線程執行), onStart() 就不適用了,因爲它總是在 subscribe 所發生的線程被調用,而不能指定線程。要在指定的線程來做準備工作,可以使用 doOnSubscribe() 方法,具體可以在後面的文中看到。

unsubscribe(): 這是 Subscriber 所實現的另一個接口 Subscription 的方法,用於取消訂閱。在這個方法被調用後,Subscriber 將不再接收事件。一般在這個方法調用前,可以使用 isUnsubscribed() 先判斷一下狀態。 unsubscribe() 這個方法很重要,因爲在 subscribe() 之後, Observable 會持有 Subscriber 的引用,這個引用如果不能及時被釋放,將有內存泄露的風險。所以最好保持一個原則:要在不再使用的時候儘快在合適的地方(例如 onPause() onStop() 等方法中)調用 unsubscribe() 來解除引用關係,以避免內存泄露的發生。

2)創建Observable(被觀察者)

Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
    @Override
    public void call(Subscriber<? super String> subscriber) {
        subscriber.onNext("Hello");
        subscriber.onNext("Hi");
        subscriber.onNext("Aloha");
        subscriber.onCompleted();
    }
});

create() 方法是 RxJava 最基本的創造事件序列的方法。基於這個方法, RxJava 還提供了一些方法用來快捷創建事件隊列,例如:

  • just(T...): 將傳入的參數依次發送出來。
Observable observable = Observable.just("Hello", "Hi", "Aloha");
// 將會依次調用:
// onNext("Hello");
// onNext("Hi");
// onNext("Aloha");
// onCompleted();
  • from(T[]) / from(Iterable<? extends T>): 將傳入的數組或 Iterable 拆分成具體對象後,依次發送出來。
String[] words = {"Hello", "Hi", "Aloha"};
Observable observable = Observable.from(words);
// 將會依次調用:
// onNext("Hello");
// onNext("Hi");
// onNext("Aloha");
// onCompleted();

3) Subscribe (訂閱)

observable.subscribe(observer);
// 或者:
observable.subscribe(subscriber);

有人可能會注意到, subscribe() 這個方法有點怪:它看起來是『observalbe 訂閱了 observer / subscriber』而不是『observer / subscriber 訂閱了 observalbe』,這看起來就像『雜誌訂閱了讀者』一樣顛倒了對象關係。這讓人讀起來有點彆扭,不過如果把 API 設計成 observer.subscribe(observable) / subscriber.subscribe(observable) ,雖然更加符合思維邏輯,但對流式 API 的設計就造成影響了,比較起來明顯是得不償失的。

Observable.subscribe(Subscriber) 的源代碼

public final Subscription subscribe(Subscriber<? super T> subscriber) {
// 首先進入這個方法,返回Subscription,好像是爲了方便 取消訂閱
    return Observable.subscribe(subscriber, this);
}


private static <T> Subscription subscribe(Subscriber<? super T> subscriber, Observable<T> observable) {

    if (subscriber == null) {
        throw new IllegalArgumentException("observer can not be null");
    }
    if (observable.onSubscribe == null) {
        throw new IllegalStateException("onSubscribe function can not be null.");
    }

    // ☆ 在這裏調用了onStart()
    subscriber.onStart();

    // 轉換爲SafeSubscriber 不知道爲什麼轉爲他 但是看名字應該是安全的意思,無非就是做了些安全的操作,懶得往下看
    if (!(subscriber instanceof SafeSubscriber)) {
        subscriber = new SafeSubscriber<T>(subscriber);
    }

    try {
        // hook.onSubscribeStart(observable, observable.onSubscribe)--> return onSubscribe
        // ☆  所以相當於調用了onSubscriber 的 call 方法
        hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);
        // 下面其實他就是直接返回 subscriber  沒有做別的操作
        return hook.onSubscribeReturn(subscriber);
    } catch (Throwable e) {
        Exceptions.throwIfFatal(e);
        // 如果執行onSubscribe出現未處理的錯誤,我們會傳播的
        try {
            subscriber.onError(hook.onSubscribeError(e));
        } catch (Throwable e2) {
            // 表示調用本身的onError失敗 , 所以就 throw 出去
            Exceptions.throwIfFatal(e2);
            RuntimeException r = new RuntimeException("Error occurred attempting to subscribe [" + e.getMessage() + "] and then again while trying to pass to onError.", e2);
            // TODO 這邊標記爲TODO ,其實看他的源碼他是直接返回了r,並沒有做什麼事情,我們其實可以在這邊自定義導致錯誤的錯誤處理
            hook.onSubscribeError(r);
            // TODO why aren't we throwing the hook's return value.
            throw r;
        } 
        return Subscriptions.unsubscribed();  // 取消訂閱
    }
}

可以看到,subscriber() 做了3件事:
>
1. 調用 Subscriber.onStart() 。這個方法在前面已經介紹過,是一個可選的準備方法。
2. 調用 Observable 中的 OnSubscribe.call(Subscriber) 。在這裏,事件發送的邏輯開始運行。從這也可以看出,在 RxJava 中, Observable 並不是在創建的時候就立即開始發送事件,而是在它被訂閱的時候,即當 subscribe() 方法執行的時候。
3. 將傳入的 Subscriber 作爲 Subscription 返回。這是爲了方便 unsubscribe().

不完整定義的回調

除了 subscribe(Observer)subscribe(Subscriber)subscribe()還支持不完整定義的回調,RxJava 會自動根據定義創建出 Subscriber 。形式如下:

Action1<String> onNextAction = new Action1<String>() {
    // onNext()
    @Override
    public void call(String s) {
            Log.d(tag, s);
    }
};
Action1<Throwable> onErrorAction = new Action1<Throwable>() {
    // onError()
    @Override
    public void call(Throwable throwable) {
      // Error handling
    }
};
Action0 onCompletedAction = new Action0() {
    // onCompleted()
    @Override
    public void call() {
        Log.d(tag, "completed");
    }
};

// 自動創建 Subscriber ,並使用 onNextAction 來定義 onNext()
observable.subscribe(onNextAction);
// 自動創建 Subscriber ,並使用 onNextAction 和 onErrorAction 來定義 onNext() 和 onError()
observable.subscribe(onNextAction, onErrorAction);
// 自動創建 Subscriber ,並使用 onNextAction、 onErrorAction 和 onCompletedAction 來定義 onNext()、 onError() 和 onCompleted()
observable.subscribe(onNextAction, onErrorAction, onCompletedAction);

簡單解釋一下這段代碼中出現的 Action1Action0Action0是 RxJava 的一個接口,它只有一個方法 call(),這個方法是無參無返回值的;由於 onCompleted() 方法也是無參無返回值的,因此Action0 可以被當成一個包裝對象,將 onCompleted() 的內容打包起來將自己作爲一個參數傳入 subscribe()以實現不完整定義的回調。這樣其實也可以看做將 onCompleted()方法作爲參數傳進了 subscribe(),相當於其他某些語言中的『閉包』。 Action1 也是一個接口,它同樣只有一個方法 call(T param),這個方法也無返回值,但有一個參數;與 Action0同理,由於onNext(T obj)onError(Throwable error)也是單參數無返回值的,因此 Action1 可以將 onNext(obj)onError(error)打包起來傳入 subscribe() 以實現不完整定義的回調。事實上,雖然Action0Action1在 API 中使用最廣泛,但 RxJava 是提供了多個 ActionX 形式的接口 (例如 Action2, Action3) 的,它們可以被用以包裝不同的無返回值的方法。

發佈了34 篇原創文章 · 獲贊 8 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章