【源碼閱讀】閱讀 "RxJava 閱讀筆記" 筆記

RxJava是什麼

是一個異步庫

RxJava好處是什麼

讓代碼簡潔,有序

RxJava的一些概念

  1. 重構的觀察者
    普通的觀察者 ObserverObservable ,構成觀察者-被觀察者關係後,觀察者回調方法只有一個。

而RxJava 的觀察者增加了

  • onNext 表示事件響應後,下一步操作
  • onError 表示事件內部處理出錯。
  • onComplete 或者成功完成觀察者的回調。
  1. RxJava 的觀察者包含 Observer 和 另一個替代 ObserverSubscriber

  2. RxJava 有4個新增概念:觀察者(Observer),被觀察者(Observable),事件,訂閱(subscribe)。

RxJava的基本用法

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!");
    }
};

RxJava提供了一個可替換的 觀察者 : Subscriber , 基本實現和Observer類似,也有些基本區別:

  1. onStart(): 這是 Subscriber 增加的方法。它會在 subscribe 剛開始,而事件還未發送之前被調用,可以用於做一些準備工作,例如數據的清零或重置。這是一個可選方法,默認情況下它的實現爲空。需要注意的是,如果對準備工作的線程有要求(例如彈出一個顯示進度的對話框,這必須在主線程執行), onStart() 就不適用了,因爲它總是在 subscribe 所發生的線程被調用,而不能指定線程。要在指定的線程來做準備工作,可以使用 doOnSubscribe() 方法,具體可以在後面的文中看到。
  2. unsubscribe(): 這是 Subscriber 所實現的另一個接口 Subscription 的方法,用於取消訂閱。在這個方法被調用後,Subscriber 將不再接收事件。一般在這個方法調用前,可以使用 isUnsubscribed() 先判斷一下狀態。 unsubscribe() 這個方法很重要,因爲在 subscribe() 之後, Observable 會持有 Subscriber 的引用,這個引用如果不能及時被釋放,將有內存泄露的風險。所以最好保持一個原則:要在不再使用的時候儘快在合適的地方(例如 onPause() onStop() 等方法中)調用 unsubscribe() 來解除引用關係,以避免內存泄露的發生。

2. 創建被觀察者

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();
    }
});

看到上面的Observable.OnSubscribe接口沒,就是他最終調用了 subscriber 的事件發送方法onNext(), onCompleted()等。

3. 使用subscribe方法讓二者建立訂閱關係

observable.subscribe(observer);

以上,就建立了觀察者和被觀察者之間的訂閱關係
其實現代碼,也給一下, 後面會用到:

// 注意:這不是 subscribe() 的源碼,而是將源碼中與性能、兼容性、擴展性有關的代碼剔除後的核心代碼。
// 如果需要看源碼,可以去 RxJava 的 GitHub 倉庫下載。
public Subscription subscribe(Subscriber subscriber) {
    subscriber.onStart();
    onSubscribe.call(subscriber);
    return subscriber;
}

除了上面的那種 Observer, 還可以給subcribe()方法傳入不完整的接口:

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);

上面的Action0, Action1, Action2 ,就是RxJava提供的自定義類型接口。都可以匿名內部類對象的形式,傳給observable.subscribe(). Action0 提供一個 call() 無參無返回值的方法, Action1 的call方法會多一個參數,他們都是對 onComplete()方法的包裝,而已,最終,會回調到 call()方法。(ps:RxJava2 好像去掉這個Action0了)

4. 創建事件序列

有了觀察者,被觀察者之間的訂閱關係,還需要產生事件,在觀察者和被觀察者之間流動對吧,所以RxJava提供了

  • create(“Hello”, “Hi”, “Aloha”)
  • just(…)
  • from(“Hello”, “Hi”, “Aloha”"")
    等方法,去創造事件序列

Scheduler

一般使用RxJava時,我們這樣用:

int drawableRes = ...;
ImageView imageView = ...;
Observable.create(new OnSubscribe<Drawable>() {
    @Override
    public void call(Subscriber<? super Drawable> subscriber) {
    
        Drawable drawable = getTheme().getDrawable(drawableRes));
        // 產生事件的位置
        subscriber.onNext(drawable);
        subscriber.onCompleted();
    }
})
.subscribeOn(Schedulers.io()) // 指定 subscribe() 發生在 IO 線程
.observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回調發生在主線程
.subscribe(new Observer<Drawable>() {
    @Override
    public void onNext(Drawable drawable) {
    // 消耗事件的位置
        imageView.setImageDrawable(drawable);
    }

    @Override
    public void onCompleted() {
    }

    @Override
    public void onError(Throwable e) {
        Toast.makeText(activity, "Error!", Toast.LENGTH_SHORT).show();
    }
});

上面,通過調用 subscribeOn(Schedulers.io()), .observeOn(AndroidSchedulers.mainThread()), 我們可以指定執行產生事件的線程Schedulers.io(), 消耗事件回調方法所在的線程AndroidSchedulers.mainThread(),那RxJava是如何做到的呢?

首先,我們要理解它的一個方法(或者叫概念,又是概念)

變換事件

RxJava內部,通過一個稍顯複雜的操作,可以“將事件序列中的對象或整個序列進行加工處理,轉換成不同的事件或事件序列“,

事件序列是啥?先來一段代碼:

Observable.just("images/logo.png") // 輸入類型 String
    .map(new Func1<String, Bitmap>() {
        @Override
        public Bitmap call(String filePath) { // 參數類型 String
        // 位置1
            return getBitmapFromPath(filePath); // 返回類型 Bitmap
        }
    })
    .subscribe(new Action1<Bitmap>() {
        @Override
        public void call(Bitmap bitmap) { // 參數類型 Bitmap
        // 位置2
            showBitmap(bitmap);
        }
    });

上面的 new Func1(), 還有 new Aciton1() 匿名類對象,都是 事件,他們會有一些事件方法,方法的參數,看着不同啊,那,代碼爲何可以從一個方法跳到另一個方法**(位置1 -》 位置2)**執行呢?

原因就是有 map() 這個方法。他可以將一個事件或者事件序列變換成另一個事件或者事件序列
具體的原理呢,後續會講到(也可能講不到)。~~!

總之,這個map()方法非常重要,也非常牛逼,先記住:map()做到了事件或者事件序列的轉換。

當然, 還有其他方法,map方法更牛逼:

  • flatMap() 非常6的一個方法,解釋起來都困難(暫時不解釋了),和map的區別是:變換後返回值是一個Observable對象。
  • throttleFirst() 每次事件觸發後的一定時間間隔內丟棄新的事件。常用作去抖動過濾,例如按鈕的點擊監聽器:

變換的原理

這一段最繞了。不過還是可以看一看。

  • 變換雖然功能各有不同,但實質上都是針對事件序列的處理和再發送。而在 RxJava 的內部,它們是基於同一個基礎的變換方法: lift(Operator)。

代碼1

// 注意:這不是 lift() 的源碼,而是將源碼中與性能、兼容性、擴展性有關的代碼剔除後的核心代碼。
// 如果需要看源碼,可以去 RxJava 的 GitHub 倉庫下載。
public <R> Observable<R> lift(Operator<? extends R, ? super T> operator) {
    return Observable.create(new OnSubscribe<R>() {
        @Override
        public void call(Subscriber subscriber) {
            Subscriber newSubscriber = operator.call(subscriber);
            newSubscriber.onStart();
            onSubscribe.call(newSubscriber);
        }
    });
}

上面一段代碼發生了神馬?爲什麼就可以執行變換事件或者事件序列的牛皮操作呢?

這裏,我把之前 subscribe()方法也拷過來,對比一下:

代碼2

// 注意:這不是 subscribe() 的源碼,而是將源碼中與性能、兼容性、擴展性有關的代碼剔除後的核心代碼。
// 如果需要看源碼,可以去 RxJava 的 GitHub 倉庫下載。
public Subscription subscribe(Subscriber subscriber) {
    subscriber.onStart();
    onSubscribe.call(subscriber);
    return subscriber;
}

這裏,代碼1那段call()方法幾乎和代碼2subscribe()方法類似 ,新生成了一個 newSubscriber(前面說過,等價於 Observer), 然後調用 onStart()方法,把 newSubscriber 關聯到舊的 onSubscribe 對象中。

  • subscribe() 中這句話的 onSubscribe 指的是 Observable 中的 onSubscribe 對象,是否還記得create 方法?
  • 當含有 lift() 時:
    1. lift() 創建了一個 Observable 後,加上之前的原始 Observable,已經有兩個 Observable 了;

    2. 而同樣地,新 Observable 裏的新 OnSubscribe 加上之前的原始 Observable 中的原始 OnSubscribe,也就有了兩個 OnSubscribe;

    3. 當用戶調用經過 lift() 後的 Observable 的 subscribe() 的時候,使用的是 lift() 所返回的新的 Observable ,於是它所觸發的 onSubscribe.call(subscriber),也是用的新 Observable 中的新 OnSubscribe,即在 lift() 中生成的那個 OnSubscribe;

    4. 而這個新 OnSubscribe 的 call() 方法中的 onSubscribe ,就是指的原始 Observable 中的原始 OnSubscribe ,在這個 call()方法裏,新 OnSubscribe 利用 operator.call(subscriber) 生成了一個新的 Subscriber(Operator 就是在這裏,通過自己的 call() 方法將新 Subscriber 和原始 Subscriber 進行關聯,並插入自己的『變換』代碼以實現變換),然後利用這個新 Subscriber 向原始 Observable 進行訂閱。
      這樣就實現了 lift() 過程,有點像一種代理機制,通過事件攔截和處理實現事件序列的變換。

第4點太繞了。

用自己的話描述,就是: Observable 執行了lift操作,形成一個新的Observable對象,代理了舊的Observable,有事件過來,先通過新的,轉發給舊的,舊的再通知代理的 Subscriber. 最後再分發給 目標 Subscriber

還是打個比方吧:

有個賣房子的中介毛利小O, 現在有個人Subscriber要找他買房子,但是他沒有房源;
於是,他只能找售樓部的中介 工藤新O, 中介 毛利小O 的買房人就成爲工藤新OSubscriber。but!中介 工藤新O很聰明,他要搞個操作對毛利小O的買房人(舊的Subscriber)進行一層關聯和變換。即:operator.call(subscriber)。生成一個新的Subscriber, 並且裏面有自己的一些操作。然後調用onSubscribe.call(newSubscriber) 把新的和舊的進行一個關聯。

接着,中介 工藤新O 就能利用新的Subscriber,實現自己的目的了(對房價實現一些不可告人的操作)了。

線程控制的原理

to be continue

參考:
給 Android 開發者的 RxJava 詳解

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章