本系列目錄:我學 rxjava - 目錄
Android 知識梳理目錄:知識梳理
啥叫 rxjava
官方文檔解釋:
RxJava:a library for composing asynchronous and event-based programs using observable sequences for the Java VM
// 翻譯:RxJava 是一個在 Java VM 上使用可觀測的序列來組成異步的、基于事件的程序的庫
通俗解釋:
// Android中的 AsyncTask 、Handler
rxjava 完成的工作就是異步,期中采用了響應式編程的理念,現在響應式編程不明白沒關系,不影響你用 rxjava 完成開發,響應式編程現在桃李滿天下呢,用不了多久就明白了并深有體會了,推薦學完 rxjava 再去看 Google 的 AAC 響應式組件,你就對響應式編程非常明白了,這里不要臉的推薦自己的文章:Android Architecture Components 開發架構
添加依賴
dependencies {
// Android 支持 Rxjava
// 此處一定要注意使用RxJava2的版本
compile 'io.reactivex.rxjava2:rxjava:2.0.1'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
// Android 支持 Retrofit
compile 'com.squareup.retrofit2:retrofit:2.1.0'
// 銜接 Retrofit & RxJava
// 此處一定要注意使用RxJava2的版本
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
// 支持Gson解析
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
}
依賴可能的錯誤如下:
請在相關 module 中的 build.gradle 中
android {
...
packagingOptions {
exclude 'META-INF/rxjava.properties'
}
}
rxjava 采用的是觀察者設計模式, 必然就是在 Observable 被觀察者 身上注冊 Observer 觀察者了,我們定義 Observable 如何產生,產生什么數據,然后 Observer 如何消費數據,整個套路基本就是這樣,當然里面有很設置和變化啦
rxjava 里面有很多沒接觸過的,不好記的關鍵字,記住這些關鍵字才能玩的轉 rxjava
關鍵字:
- 被觀察者(Observable) 產生事件 顧客
- 觀察者(Observer) 接收事件,并給出響應動作 廚房
- 訂閱(Subscribe) 連接 被觀察者 & 觀察者 服務員
- 事件(Event) 被觀察者 & 觀察者 溝通的載體 菜式
創建 Observable 被觀察者對象
rxjava 中的 Observable 被觀察者一般都是要傳入數據,或是能產生數據的對象才能創建出來的,所以我也喜歡管 Observable 叫數據源,要是沒有 Observable 這個數據源提供數據,后面怎么消費數據呢
// 傳入可以產生數據的對象方式創建 Observable 對象
Observable<String> object = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
// emitter 是用來提供數據的,我們也叫發射
emitter.onNext("數據");
}
});
// 直接用數據創建 Observable 對象,數據可以是單個也可以是動態數組,集合
Observable<String> just = Observable.just("aaa");
Observable<String> list = Observable.just("", "", "");
創建 Observer 觀察者并定義處理事件的行為
Observer<String> observer = new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
// 觀察者在接受到數據之前,先執行該方法
}
@Override
public void onNext(String value) {
// 觀察者此時接受到數據,可以處理數據了
}
@Override
public void onError(Throwable e) {
// 觀察者接受到錯誤信號,進行相關處理
}
@Override
public void onComplete() {
// 觀察者此時已經處理完數據了,執行該方法最最后的收尾工作。
}
};
Observer 觀察者里面有4個方法,上面的方法里的文字基本描述清楚了,然后我想說下 Error 錯誤信號可以用前面 數據源里面的 emitter.onError(xxx) 自己發射出來,也會接受到這個過程中系統拋出的異常。onComplete 是不管什么情況最后都會走的。
現在 Observable 有了 ,Observer 也有了,他倆一注冊就成了。
observable.subscribe(observer);
我們要注意數據產生的點,Observable 只是提供數據,不是我們創建一個 Observable 對象就去獲取數據,發射數據了,而是再 Observer 注冊到 Observable 身上那一瞬間,Observable 才還是提供數據,是遠程數據的開始從遠程獲取數據,是現成數據的開始發射數據給 Observer 消費數據。
線程變換
觀察者設計模式只是對 數據源 和 數據消費者 的一種組織形式,還不是 rxjava 最核心的內容,大家可以不要忘了 rxjava 可是替代 asynctask ,handle 這樣的異步線程啊,方便的多線程操作和切換才是 rxjava 最大的核心內容
rxjava 提供一下幾個線程池:
- Schedulers.immediate()
當前線程 - AndroidSchedulers.mainThread()
Android主線程 - Schedulers.newThread()
常規新線程 - Schedulers.io()
io操作線程,可以進行網絡請求、讀寫文件等io密集型操作 - Schedulers.computation()
CPU計算操作線程,線程數據同 CPU 核心數
相關的線程控制 API 如下,這里是簡單的寫的
observable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
- subscribeOn 是描述 observable 中產生數據的方法執行在哪個線程
- observeOn 是描述 observer 消費數據的方法執行在哪個線程
- 這里 數據源是從網絡獲取數據,UI 線程消費數據
關于 Observer 的變形
我們按照上面的 方式創建一個 Observer 來,需要實現4個方法才行,豐富多看著亂,頁影響 rxjava 的鏈式調用閱讀效果,官方提供了如下的 Observer 創建方法
// 表示觀察者不對被觀察者發送的事件作出任何響應(但被觀察者還是可以繼續發送事件)
public final Disposable subscribe()
// 表示觀察者只對被觀察者發送的Next事件作出響應
public final Disposable subscribe(Consumer<? super T> onNext) {}
// 表示觀察者只對被觀察者發送的Next事件 & Error事件作出響應
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError) {}
// 表示觀察者只對被觀察者發送的Next事件、Error事件 & Complete事件作出響應
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete) {}
// 表示觀察者只對被觀察者發送的Next事件、Error事件 、Complete事件 & onSubscribe事件作出響應
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete, Consumer<? super Disposable> onSubscribe) {}
// 表示觀察者對被觀察者發送的任何事件都作出響應
public final void subscribe(Observer<? super T> observer) {}
Consumer 是一個方法包裝接口,Observer 中的4個方法對應 4個 Consumer 方法包裝接口,subscribe 注冊方法中可以接受 1 - 4個 Consumer 可變參數,根據下面圖 4個方法的順序,傳入一個是代替 onNext 方法,傳入2個是代替 onNext、onError 方法
關于可能的內存泄露的處理
這些注冊的 Observer 我們都是在 activity 中進行的,按照:匿名內部類持有外不累的引用,這個注冊的匿名 Observer 對象其實是把我們的 activity 帶出 activity 的生命周期外去了,Observable 持有這些注冊的 Observer 對象引用,那么間接的也持有了 activity 的引用,在 activity 關閉時這就是個麻煩事了,原因不就是老生常談的內存泄露了嘛...
針對這個情況,其實我們是游處理辦法的,那就是 Disposable 管道這個對象,Disposable 是實際管理 Observable和 Observer 關系的操作類,我們用 Disposable 就可以接觸 Observable 和 Observer 的注冊的關系。
Disposable 有2種獲取方式,一個是注冊時我們使用 Consumer 代替 Observer ,然后我們就可以獲取這個 Disposable 對象,調用 disposable.dispose() 就可以解綁
Disposable disposable = Observable
.just("22")
.subscribe(
new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
}
}
, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
}
});
disposable.dispose();
或者是 Observer 對象中的 onSubscribe(Disposable d) 方法中,我們可以獲取到 Disposable 對象
若是我們有多個 disposable 對象,我們可以使用官方提供管理類
CompositeDisposable compositeDisposable = new CompositeDisposable();
// 添加 disposable 管道對象用于統一管理
compositeDisposable.add( disposable );
// 統一解綁
compositeDisposable.dispose();
一個完成的流程示例
rxjava 2 中添加了不少 doOnXXX 方法,打都是在指定的 OnXXX 方法之前執行的。
需要注意的是 2個 observeOn 方法中間夾一個 doOnNext 方法,這是說前一個 observeOn 指定 這個 doOnNext 方法的執行線程,后一個 observeOn 方法執行最終執行 Observer 執行線程,其實這個就是 rxjava 的變換操作符的基礎
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
Log.d(TAG, " subscribe.../thread: " + Thread.currentThread().getName() + "處理數據,產生事件");
e.onNext("HH");
}
})
.subscribeOn(Schedulers.io())
.doOnSubscribe(new Consumer<Disposable>() {
@Override
public void accept(Disposable disposable) throws Exception {
Log.d(TAG, " doOnSubscribe.../thread: " + Thread.currentThread().getName() + "預熱方法(doOnSubscribe函數),最先執行");
}
})
.observeOn(Schedulers.computation())
.doOnNext(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.d(TAG, " doOnNext.../thread: " + Thread.currentThread().getName() + "數據處理后,先執行我,再發射數據");
}
})
.observeOn(Schedulers.newThread())
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
Log.d(TAG, " onSubscribe.../thread: " + Thread.currentThread().getName() + "預熱方法(觀察者),最先執行");
}
@Override
public void onNext(@NonNull String s) {
Log.d(TAG, " onNext.../thread: " + Thread.currentThread().getName() + "接受數據,消費事件");
}
@Override
public void onError(@NonNull Throwable e) {
}
@Override
public void onComplete() {
}
});
一個完整的簡單實用就是這樣了,這里各種生命周期函數寫的比較全了,直接看結果:
按照執行順序:
- doOnSubscribe() 方法最先執行,所在線程是UI 線程,調用測試方法的線程
- subscribe / onSubscribe() ,之后是觀察者新添加方法,所在線程也是UI 線程,和doOnSubscribe()一樣,這倆用一個就行
- create / subscribe() ,接下來是處理數據,發射事件的線程
- doOnNext(),這個是在數據發射之前執行的,我們可以指定一個線程,這里指定的計算線程,要是不注定,則使用發射事件的線程
- Observer / onNext(),最后就是我們接受事件啦。
注意上面各種方法所在線程,不要弄混了