最近工作用Rxjava,發現有些東西忘記了,翻了翻資料,纔想起來。可能是年紀大了記性不好,所以在這裏寫下來,以後在需要查資料就不用去到處找了,直接看自己的博客就好了。
依賴
在安卓中,除了依賴RxJava外,還需要依賴一下RxAndroid
compile 'io.reactivex.rxjava2:rxandroid:2.1.0'
compile 'io.reactivex.rxjava2:rxjava:2.1.0'
鑑於RxJava源碼比較多,本系列不會分析源碼,主要介紹一些常用到的東西
1. RxJava簡要介紹
RxJava中有三個關鍵點
Observable,被觀察者
Observer,觀察者
subscribe,建立訂閱關係
在觀察者模式中,一般都是觀察者訂閱被觀察者
但在RxJava中,是Observable.subscribe(Observer)
被觀察者有變化,觀察者就會知道。
有一個類比水管的說法,水管說:
RxJava事件流向.png
Observable,上游水管
Observer,下游水管
subscribe,連接上下游的水管
水管接上之後,上游水管裏的水流動,下流水管裏的水就會流動。
2. 基本使用
廢話不多說,先來一段代碼感受一下
//關注點1
Observable<String> observable=Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
Log.d("TAG","subscribe");
emitter.onNext("1");
emitter.onNext("2");
emitter.onNext("3");
emitter.onComplete();
}
});
//關注點2
Observer<String> observer=new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log.d("TAG","onSubscribe");
}
@Override
public void onNext(String s) {
Log.d("TAG",s);
}
@Override
public void onError(Throwable e) {
Log.d("TAG","onError");
}
@Override
public void onComplete() {
Log.d("TAG","onComplete");
}
};
//關注點3
observable.subscribe(observer);
這段代碼的執行結果
D/TAG: onSubscribe
D/TAG: subscribe
D/TAG: 1
D/TAG: 2
D/TAG: 3
D/TAG: onComplete
站在水管的角度
把關注點1比喻成一根水管,處在上游
把關注點2也比喻成一根水管,處在下游
關注點3就是連接這兩根水管的一個媒介,通過該媒介關注點1和關注點2就連通了。
我們在來看看剩下的兩個比較陌生的類
ObservableEmitter和Disposable
ObservableEmitter
這是一個接口,繼承自Emitter接口,翻譯過來就是發射器的意思,而它就是用來發出事件的,通過調用emitter的onNext(T value),
onError(Throwable t)和onComplete()分別用來發生next事件,error事件和complete事件。
下面來總結一下事件的發送接收規則
- 事件是發送一個,接收一個,然後才發送下一個。
- 上游可以發送無限個next事件,下游也可以接收無限個next事件。
- 當上遊發送complete或者error事件後,下游不會在接收complete或者error事件之後的事件,但上游會將全部事件都發送完。
- 上游的complete和error事件必須唯一且互斥,否則可能相應的事件不會被下游接收到,並且可能會發生手機崩潰的情況。
Disposable(這一點不是最常用的一部分,瞭解一下就好了)
Disposable是一個接口,裏面就兩個方法
void dispose();
boolean isDisposed();
修改關注點1和關注點2的代碼
//關注點1
Observable<String> observable=Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
Log.d("TAG","subscribe");
emitter.onNext("1");
emitter.onNext("2");
emitter.onComplete();
emitter.onNext("3");
Log.d("TAG","emitter 3");
}
});
//關注點2
Observer<String> observer=new Observer<String>() {
Disposable disposable;
@Override
public void onSubscribe(Disposable d) {
Log.d("TAG","onSubscribe");
disposable=d;
}
@Override
public void onNext(String s) {
Log.d("TAG",s);
if(s.equals("1")){
disposable.dispose();
Log.d("TAG", "isDisposed : " + disposable.isDisposed());
}
}
@Override
public void onError(Throwable e) {
Log.d("TAG","onError:"+e.getMessage());
}
@Override
public void onComplete() {
Log.d("TAG","onComplete");
}
};
輸出結果
D/TAG: onSubscribe
D/TAG: subscribe
D/TAG: 1
D/TAG: isDisposed : true
D/TAG: emitter 3
結果分析
當在下游調用disposable.dispose()方法時,下游將不會在接收後續的事件,但上游還是會將全部事件發送完畢。
這裏的dispose就相當於將水管切斷了,因此接收不了後續事件。
鏈式調用(上面講了那麼多,其實最重要的事這一部分,我們常用的就是這一部分。)
我們來稍微修改一下之前的寫法,就變成了RxJava流行的鏈式調用寫法了。
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
}
}).subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String s) {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
上面的寫法就是常用的鏈式寫法,但是還有一點小問題,就是默認被觀察者和觀察者都是在主線程中運行的,如果我們用它來做耗時操作,就要放在子線程中,操作完成之後又要轉到主線程去更新UI,這樣又要用handler,線程切換比較麻煩。其實Rxjava已經爲我們處理了。
observable有兩個方法分別指定被觀察者和觀察者代碼運行 線程。
observable.subscribeOn(Schedulers.io());//指定被觀察者運行在子線程。(上游水管)
observable.observeOn(AndroidSchedulers.mainThread());//指定觀察者運行在主線程。(下游水管)
RxJava已經爲我們提供了一下幾個Scheduler
- Schedulers.immediate():直接在當前線程運行,相當於不指定線程。這是默認的 Scheduler。
- Schedulers.newThread():總是啓用新線程,並在新線程執行操作。
- Schedulers.io(): I/O 操作(讀寫文件、讀寫數據庫、網絡信息交互等)所使用的 Scheduler。行爲模式和 newThread() 差不多,區別在於 io() 的內部實現是是用一個無數量上限的線程池,可以重用空閒的線程,因此多數情況下 io() 比 newThread() 更有效率。不要把計算工作放在 io() 中,可以避免創建不必要的線程。
- Schedulers.computation():計算所使用的 Scheduler。這個計算指的是 CPU 密集型計算,即不會被 I/O 等操作限制性能的操作,例如圖形的計算。這個 Scheduler 使用的固定的線程池,大小爲 CPU 核數。不要把 I/O 操作放在 computation() 中,否則 I/O 操作的等待時間會浪費 CPU。
- AndroidSchedulers.mainThread():它指定的操作將在 Android 主線程運行。
可以根據自己的需要去選擇被觀察者和觀察者所在的線程。
鏈式編程
Observable.create(new ObservableOnSubscribe<Object>() {
@Override
public void subscribe(ObservableEmitter<Object> e) throws Exception {
Log.i("ceshi", "subscribe " + Thread.currentThread().getName());
e.onNext("好好學習,天天向上");
}
}).subscribeOn(Schedulers.io())//指定被觀察者運行的線程。
.observeOn(AndroidSchedulers.mainThread())//指定觀察者運行的線程。
.subscribe(new Observer<Object>() {
@Override
public void onSubscribe(Disposable d) {
Log.i("ceshi", "onSubscribe d = " + d + Thread.currentThread().getName());
}
@Override
public void onNext(Object value) {
Log.i("ceshi", "onNext value = " + value + " " + Thread.currentThread().getName());
}
@Override
public void onError(Throwable e) {
Log.i("ceshi", "onError e = " + e.toString() + " " + Thread.currentThread().getName());
}
@Override
public void onComplete() {
Log.i("ceshi", "onComplete ");
}
});
運行的結果
11-29 10:50:58.272 23384-23384/com.airbridge.rxjavademo I/ceshi: onSubscribe d = 0main
11-29 10:50:58.274 23384-23523/com.airbridge.rxjavademo I/ceshi: subscribe RxCachedThreadScheduler-1
11-29 10:50:58.278 23384-23384/com.airbridge.rxjavademo I/ceshi: onNext value = 好好學習,天天向上 main
11-29 10:50:58.278 23384-23384/com.airbridge.rxjavademo I/ceshi: onComplete
這就是我們常用的鏈式編程方式,下一篇我們來講一下背壓問題。下一篇講背壓的博客:Rxjava的使用_2(背壓問題)
如果需要上面的源碼,可以去下載 RxjavaDemo.zip
本篇中有一部分截圖和代碼是從這個https://www.jianshu.com/p/9561ebdc5c0b哥們兒博客裏面借用的。大家也可以去看的博客。