Android進階系列之第三方庫知識點整理。
知識點總結,整理也是學習的過程,如有錯誤,歡迎批評指出。
寫這篇文章的時候,Rxjava3
已經出來了,二者差別不是特別大,所以還是基於Rxjava2
進行總結,後續會花時間來總結Rxjava3
的一些改變。
基礎概念
1、什麼是Rx
ReactiveX
是Reactive Extensions的縮寫,一般簡寫爲Rx,最初是LINQ的一個擴展,Rx是由由微軟開發並開源的一個編程模型,目標是提供一致的編程接口,幫助開發者更方便的處理異步數據流,Rx庫支持很多語言,而 Rxjava
是Rx庫基於Java語言提供的函數庫。
官網顯示支持的語言列表:
2、觀察者模式
觀察者模式(Observer),又叫發佈-訂閱模式(Publish/Subscribe),定義對象間一種一對多的依賴關係,使得每當一個對象改變狀態,則所有依賴於它的對象都會得到通知並自動更新,觀察者模式屬於行爲型模式。
我需要打電話跟小明說他被戴綠帽這事,但是我又怕打電話過去他可能在忙,所以我直接給他發信息,讓他有時間了再給我回電話,這樣,當小明有時間了可能就會給我回電話,他給我回電話,我再含着淚的告訴他要堅強。
在上面這個例子中,小明就是被觀察者,我是觀察者,我發短信告訴他有時間回我電話這個操作就是訂閱,這樣我跟他有了依賴關係,當他有時間後,就會回我帶電話,我這邊響應式的執行後續的操作。
3、響應式(Reactive Programming)編程
一般來說,編程就是爲了處理問題,解決問題就可以有不同的視角和思路,其中具有普適性的模式就會歸結一種編程思想,我們常說的面向對象,面向過程都是一種編程思想。
響應式編程是一種通過異步和數據流來構建事務關係的編程模式
這裏麪包含的兩個核心概念:
異步:不需要等待處理完成便立刻返回,通過回調將處理結果帶回。能提高吞吐量,提高性能和效率。
數據流:就是按照時間線的事件序列,任何東西都可以看做是一個stream。在這個基礎上通過函數來過濾(filter)、選擇(select)、變換(transform)、結合(combine)這些stream。通過定義事件處理器,來異步捕獲感興趣的stream,即監聽(訂閱)stream,也叫就是註冊觀察者。
再對比我們前面的觀察者模式看,觀察者模式中被觀察者和觀察者之間通過訂閱產生依賴,訂閱這層關係相當於在二者之前挖了一道水渠,被觀察者是上游,觀察者是下游,這樣被觀察者發生改變時候,會將數據流源源不斷的發送到產生依賴關係的觀察者,通常觀察者和被觀察者是處於同一個線程中,但是響應式編程重點在異步上,即上游和下游可以在不同的線程中工作。
我們可以看一下官網的動圖:
4、Rxjava概念及簡單使用
Rxjava
採用了響應式編程模式,它在觀察者模式基礎上進行擴展,方便我們的異步
操作,觀察者與被觀察者產生訂閱關係後,被觀察者將數據流發送給觀察者的時候,Rxjava
提供了豐富的操作符來對數據流進行過濾(filter)、選擇(select)、變換(transform)、結合(combine)等等操作,然後再將處理後的數據發送給觀察者,又由於其特別棒的鏈式調用,讓邏輯在很複雜的情況下,也能很清晰的通過代碼表達出來。
我們先引入rxjava
implementation "io.reactivex.rxjava2:rxjava:2.2.8"
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
直接先來一個簡單的例子:
// 通過 Observable 創建一個被觀察者
Observable mObservable = Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
emitter.onComplete();
}
});
// 通過Observer創建一個觀察者
Observer mObserver = new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
LogUtil.d(TAG + "--onSubscribe");
}
@Override
public void onNext(Integer o) {
LogUtil.d(TAG + "--onNext o=" + o);
}
@Override
public void onError(Throwable e) {
LogUtil.d(TAG + "--onError");
}
@Override
public void onComplete() {
LogUtil.d(TAG + "--onComplete");
}
};
// 產生訂閱關係
mObservable.subscribe(mObserver);
再看看Rxjava
強大的鏈式調用:
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
emitter.onComplete();
}
// 這裏直接通過subscribe將二者鏈式調用起來
}).subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
LogUtil.d(TAG + "--Observer--onSubscribe");
}
@Override
public void onNext(Integer o) {
LogUtil.d(TAG + "--Observer--onNext o=" + o);
}
@Override
public void onError(Throwable e) {
LogUtil.d(TAG + "--Observer--onError");
}
@Override
public void onComplete() {
LogUtil.d(TAG + "--Observer--onComplete");
}
});
我們前面說,RxJava
是拓展於觀察者模式的響應式編程,所以在Rxjava
中,就有觀察者、被觀察者以及二者通過訂閱產生的依賴關係。
通過上面代碼,可以看到:
被觀察者 ——————> Observable
觀察者 ——————> Observer
訂閱關係:Observable
————> subscribe
<———— Observer
在上游的 Observable
(被觀察者)中通過 emitter
(發射器)就可以不斷地給下游的 Observer
(觀察者)傳送數據流,我們在上游發射了 1、2、3還有發射了一個 onComplete
事件。
我們通過日誌可以看到,在下游的 Observer
(觀察者)成功的接收到了上游發送的數字1、2、3包括通過調用 onComplete()
方法來接收上游發送的 onComplete
事件。
通過上面一個簡單的例子,我們可以總結出以下幾點
4.1、解耦
我們可以看到被觀察者和觀察者都是獨立存在的。
Observable
(被觀察者):
// 通過 Observable 創建一個被觀察者
Observable mObservable = Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
emitter.onComplete();
}
});
Observer
(觀察者):
// 通過Observer創建一個觀察者
Observer mObserver = new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
LogUtil.d(TAG + "--onSubscribe");
}
@Override
public void onNext(Integer o) {
LogUtil.d(TAG + "--onNext o=" + o);
}
@Override
public void onError(Throwable e) {
LogUtil.d(TAG + "--onError");
}
@Override
public void onComplete() {
LogUtil.d(TAG + "--onComplete");
}
};
可以看到,二者各自獨立存在,各幹各的事,只是通過 subscribe
來建立依賴關係,這樣的話,可以很好地實現代碼的複用,比如我們可以創建多個Observer
(觀察者),和Observable
(被觀察者)之間通過訂閱建立依賴關係後,就能實現Observable
(被觀察者)發送的數據流被多個Observer
(觀察者)接收。
4.2、數據流轉換(操作符的使用)
第二、Observable
(被觀察者)通過 emitter
(發射器)將數據以流的形式發送給Observer
(觀察者),前面講了,既然是以流的形式,那我們是不是可以在觀察者接收數據之前,對數據進行處理呢?答案是肯定的,這也是Rxjava
的強大之一,它可以通過各種操作符來對數據進行處理,我們先講一個簡單的來。
這裏只是簡單的演示一些Rxjava
對數據流的操作,後面會具體講操作符,圖片中可以看到,我們被觀察者明明發射的是一個int型的數值100,但是通過map操作符進行數據流進行轉換後,下游的消費者接收到的竟然是String的,這裏只是一個小Demo,在Rxjava中,還有各種很強大的操作符來對數據進行各種變態式的處理。
上游被觀察者
Observable
發射數據,下游除了使用Observer
來接收數據外,還可以使用消費者Consumer
來接收數據,可以看Consumer
只有一個accept
方法。
先貼一下Rxjava
強大的操作符列表,是不是很多?不要被嚇到,越多所以我們可以越方便的對數據流進行各種各樣的操作,這個後面會單獨再講解。
4.3、線程切換
我們前面說了,Rxjava
能更好的異步操作,我們先用上面的例子打印一下他們當前所在的線程情況。
結果:
可以到,統一戰線的都在主線程,我們來看看,怎麼實現異步。
同樣是那個例子,我們添加了下面這兩個代碼
subscribeOn(Schedulers.io())
observeOn(AndroidSchedulers.mainThread())
subscribeOn : 指定上游執行的線程
observeOn:指定觀察者或者消費者執行線程
結果:
代碼中,我們指定上游在io
線程,而下游在主線程執行,就這麼簡單的兩行代碼,就實現了線程切換,實現了異步操作,爽不爽?
當然,我們不光可以指定io
線程,Schedulers
還提供了其他的線程供我們選擇。
我們簡單看一個Single
線程的源碼:
是不是很熟悉?就是通過線程池來創建了一個單線程,其他類似,都是通過線程池來創建,您可以簡單去分析一下,當然,如果你對線程池還不熟悉的話,這篇 多線程(三)、線程池 ThreadPoolExecutor 知識點總結 可能適合你看看。
總結
Rxjava
的東西還挺多的,這篇先簡單的走了一遍Rxjava
的基礎概念還有簡單的使用,關於Rxjava
裏面還有其他的觀察者模式的創建,背壓,各種操作符的使用、實戰等等騷操作,下篇繼續。