RxJava官方Github地址沒有任何資料能比官方更棒的了,快去看看吧。
看 大神拋物線的講解RxJava1.x的講解,然後去使用,結果發現官方已經重構了RxJava,推出全新的2.+版本。
介紹
-
RxAndroid是RxJava在Android上的一個擴展,大牛JakeWharton的項目。據說和Retorfit、OkHttp組合起來使用,效果不是一般的好。而且用它似乎可以完全替代eventBus和OTTO,這麼牛的東西當然要研究研究了
,看看它到底有多厲害。 -
RxJava是幹嘛的:Rx(Reactive Extensions)是一個庫,用來處理事件和異步任務,在很多語言上都有實現,RxJava是Rx在Java上的實現。簡單來說,RxJava就是處理異步的一個庫,最基本是基於觀察者模式來實現的。通過Obserable和Observer的機制,實現所謂響應式的編程體驗。
Android的童鞋都知道,處理異步事件,現有的AsyncTask、Handler,不錯的第三方事件總線EventBus、OTTO等等都可以處理。並且大部分童鞋應該都很熟練了。而且經我目前的學習來看,RxJava這個庫,上手確實有門檻,不是拿來就能用。但是作爲一個猿,那些可能出現的優秀的框架技術,及時的跟進和學習是必要的,從中汲取營養才能幫助自己成長。況且有童鞋已經表示,它完全可以替代EventBus和OTTO,來看看吧。 -
RxJava的優勢
最概括的兩個字:簡潔。而且當業務越繁瑣越複雜時這一點就越顯出優勢——它能夠保持簡潔。
簡單的demo看不出來,真正投入項目使用了應該就有體會了。它提供的各種功能強悍的操作符真的很強大。
記住幾個單詞:
被觀察者Observable
觀察者Observer
訂閱subscribe
取消訂閱Disposable
別被這幾個單詞給繞暈了哈,其實沒想象中的那麼難,剛開始就是背單詞繞暈了覺得好難啊,理清思路後發現很容易理解的,其實就是異步操作+各種回調。
可以這樣理解:被觀察者Observable就像小偷,觀察者Observer就像警察,訂閱subscribe就像警察時刻觀察者小偷,一旦小偷有任何動作,警察馬上作出應對;小偷有可能做出一連續的動作,警察就必須對應做出一連續的應對。
一、添加依賴
目前最新版本
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation 'io.reactivex.rxjava2:rxjava:2.2.7'
二、單獨使用
2.+比1.+多了Disposable
(當然多的可不止這一個哈),它可以用來主動取消訂閱dispose()、查詢是否解除訂閱 true 代表 已經解除訂閱isDisposed()。
xjava雖然好用,但是總所周知,容易遭層內存泄漏。也就說在訂閱了事件後沒有及時取閱,導致在activity或者fragment銷燬後仍然佔用着內存,無法釋放。而disposable便是這個訂閱事件,可以用來取消訂閱。
1、基本使用 + 主動解除訂閱 Disposable.dispose()
整體樣子長這樣滴,必須自己慢慢敲一遍代碼纔能有一定的理解:
-
初始化被觀察者Observable:使用 Observable.create(ObservableOnSubscribe
source),必須實現subscribe()方法。 -
訂閱subscribe():給被觀察者綁定觀察者Observer,使用subscribe(Observer<? super T>
observer); -
初始化觀察者Observer;
//1、初始化被觀察者Observable:使用 create()
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
}
//2、訂閱subscribe():給被觀察者綁定觀察者Observer
}).subscribe(new Observer<Integer>() { //3、初始化觀察者Observer
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Integer integer) {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
接下來就是加入我們的邏輯啦:
//1、初始化被觀察者Observable:使用create()
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
Log.e(TAG, "Observable emit 1" + "\n");
Log.e(TAG, "subscribe中isDisposable:" + emitter.isDisposed()+ "\n");
emitter.onNext(1);
Log.e(TAG, "Observable emit 2" + "\n");
Log.e(TAG, "subscribe中isDisposable:" + emitter.isDisposed()+ "\n");
emitter.onNext(2);
Log.e(TAG, "Observable emit 3" + "\n");
Log.e(TAG, "subscribe中isDisposable:" + emitter.isDisposed()+ "\n");
emitter.onNext(3);
Log.e(TAG, "Observable emit 4" + "\n");
Log.e(TAG, "subscribe中isDisposable:" + emitter.isDisposed()+ "\n");
emitter.onNext(4);
Log.e(TAG, "Observable emit 5" + "\n");
Log.e(TAG, "subscribe中isDisposable:" + emitter.isDisposed()+ "\n");
emitter.onNext(5);
}
//2、訂閱subscribe():給被觀察者綁定觀察者Observer
}).subscribe(new Observer<Integer>() { //3、初始化觀察者Observer
private int i;
private Disposable mDisposable;
@Override
public void onSubscribe(Disposable d) {
mDisposable = d;
Log.e(TAG, "onSubscribe中isDisposable:" + d.isDisposed()+ "\n");
}
@Override
public void onNext(Integer integer) {
i++;
if (i == 2) {
// 在RxJava 2.x 中,新增的Disposable可以主動解除訂閱,
// 讓Observer觀察者不再接收Observable被觀察者的事件
Log.e(TAG, "onNext中dispose()之前,isDisposable:" + mDisposable.isDisposed()+ "\n");
mDisposable.dispose();
Log.e(TAG, "onNext中dispose()之後,isDisposable:" + mDisposable.isDisposed()+ "\n");
}
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "onError中isDisposable:" + mDisposable.isDisposed()+ "\n");
Log.e(TAG, "onError : value : " + e.getMessage() + "\n" );
}
@Override
public void onComplete() {
Log.e(TAG, "onComplete中isDisposable:" + mDisposable.isDisposed()+ "\n");
Log.e(TAG, "onComplete" + "\n" );
}
});
運行結果:
這裏就是RxJava最基本的寫法,還要再說一下,subscribe的方法重載,subscribe()方法裏什麼參數也不放是空實現,也就是說被觀察者無論發生什麼,觀察者都不關心。
如果觀察者只關心onNext方法裏的內容,可以直接重載subscribe(Consumer<? spuer T> onNext)這個方法,會減少代碼。
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
}
}).subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
//回調後在UI界面上展示出來
}
});
2、被觀察者使用onComplete()
被觀察者使用onComplete()表示觀察者完成訂閱,即觀察者會調用onComplete()方法:
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
Integer[] integers = {0, 1, 2, 3, 4};
for (int i = 0; i < integers.length; i++) {
Log.d(TAG, "=====第" + i + "次,發:" + i);
emitter.onNext(integers[i]);
if (i == 1) {
emitter.onComplete();
}
}
}
}).subscribe(new Observer<Integer>() {
int i = 0;
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "Observer的onSubscribe");
}
@Override
public void onNext(Integer integer) {
Log.d(TAG, "第" + i + "次,收:" + integer);
i++;
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "Throwable");
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete");
}
});
注意:
emitter.onNext(integers[i]);
if (i == 3) {
emitter.onComplete();
}
一旦調用onComplete()
則觀察者會執行完成方法。
運行結果:
當調換onComplete()
與onNext(integers[i])
的順序:
if (i == 1) {
emitter.onComplete();
}
Log.d(TAG, "=====第" + i + "次,發:" + i);
emitter.onNext(integers[i]);
運行結果:
總結:當調用emitter.onComplete();
後訂閱關係表示完成,觀察者將不會做出響應,但並不影響被觀察者。上游的onNext對應下游的OnNext,上游的onComplete對應下游的onComplete。
還沒懂那看看RxJava2.0——從放棄到入門 - 簡書- 肖邦kaka
3、觀察者使用dispose()
觀察者使用dispose()取消訂閱,觀察者不會調用onComplete():
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
Integer[] integers = {0, 1, 2, 3, 4};
for (int i = 0; i < integers.length; i++) {
Log.d(TAG, "=====第" + i + "次,發:" + i);
emitter.onNext(integers[i]);
}
}
}).subscribe(new Observer<Integer>() {
Disposable disposable;
int i = 0;
@Override
public void onSubscribe(Disposable d) {
disposable = d;
Log.d(TAG, "賦值disposable:dispose0 = " + disposable.isDisposed());
Log.d(TAG, "Observer的onSubscribe");
}
@Override
public void onNext(Integer integer) {
Log.d(TAG, "第" + i + "次,收:" + integer);
Log.d(TAG, "dispose1 = " + disposable.isDisposed());
if(i==2){
disposable.dispose();
}
Log.d(TAG, "dispose2 = " + disposable.isDisposed());
i++;
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "Throwable");
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete");
}
});
運行結果:
可以看到當執行完
if(i==2){
disposable.dispose();
}
之後dispose2 = true
,觀察者已經不再處理事件了,因爲此方法已經取消了訂閱。
4、被觀察者的onComplete()+觀察者的dispose()
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
Integer[] integers = {0, 1, 2, 3, 4};
for (int i = 0; i < integers.length; i++) {
if (i == 1) {
emitter.onComplete();
}
Log.d(TAG, "=====第" + i + "次,發:" + i);
emitter.onNext(integers[i]);
}
}
}).subscribe(new Observer<Integer>() {
Disposable disposable;
int i = 0;
@Override
public void onSubscribe(Disposable d) {
disposable = d;
Log.d(TAG, "賦值disposable:dispose0 = " + disposable.isDisposed());
Log.d(TAG, "Observer的onSubscribe");
}
@Override
public void onNext(Integer integer) {
Log.d(TAG, "第" + i + "次,收:" + integer);
Log.d(TAG, "dispose1 = " + disposable.isDisposed());
if(i==2){
disposable.dispose();
}
Log.d(TAG, "dispose2 = " + disposable.isDisposed());
i++;
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "Throwable");
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete");
}
});
運行結果:
總結:
1、被觀察者使用一次onNext()
,對應的觀察者就會調用一次onNext()
,同理onComplete()
這些一樣的。
2、被觀察者使用onComplete()
,觀察者運行onComplete()
之後就不再做處理了。
3、觀察者使用disposable.dispose();
,觀察者不會運行onComplete()
,直接不對被觀察者的動作做出反應。
二、線程切換
RxJava 中已經內置了很多線程選項供我們選擇,例如有:
1、Schedulers.io() 代表io操作的線程, 通常用於網絡,讀寫文件等io密集型的操作;
2、Schedulers.computation() 代表CPU計算密集型的操作, 例如需要大量計算的操作;
3、Schedulers.newThread() 代表一個常規的新線程;
4、AndroidSchedulers.mainThread() 代表Android的主線程
推薦查看教你輕鬆理解Rxjava之線程切換流程(observeOn與subscribeOn) - wenyingzhi的博客 - CSDN博客 輕鬆理解線程切換流程。當然你也可以這裏滴。
整體樣子張這樣滴:
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
}
}).subscribeOn(Schedulers.io())
.map(new Function<Integer, Integer>() {
@Override
public Integer apply(Integer integer) throws Exception {
return integer;
}
}).doOnSubscribe(new Consumer<Disposable>() {
@Override
public void accept(Disposable disposable) throws Exception {
}
}).subscribeOn(AndroidSchedulers.mainThread())
.doOnSubscribe(new Consumer<Disposable>() {
@Override
public void accept(Disposable disposable) throws Exception {
}
}).subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.flatMap(new Function<Integer, ObservableSource<Integer>>() {
@Override
public ObservableSource<Integer> apply(Integer integer) throws Exception {
return Observable.fromArray(integer);
}
}).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Integer bytes) {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
別被這個樣子給嚇住了,只是一口氣使用了很多切換線程+操作符而已,沒問題滴。
看我們不停地切換線程吧,接下來加入我們的處理,主要就是打印出每次的線程具體是哪一個:
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
Log.d(TAG, "4、Observable的create:" + Thread.currentThread().getName());
e.onNext(1);//發射數據,向下走
}
}).subscribeOn(Schedulers.io())//S1、subscribeOn切換訂閱線程, io操作的線程
.map(new Function<Integer, Integer>() {//map:數據流的操作符,主要是對數據處理
@Override
public Integer apply(Integer integer) throws Exception {
Log.d(TAG, "5、map:" + Thread.currentThread().getName());
return integer;
}
}).doOnSubscribe(new Consumer<Disposable>() {
@Override
public void accept(Disposable disposable) throws Exception {
Log.d(TAG, "3、doOnSubscribe1:" + Thread.currentThread().getName());
}
}).subscribeOn(AndroidSchedulers.mainThread())//S2、subscribeOn切換訂閱線程, Android的主線程
.doOnSubscribe(new Consumer<Disposable>() {
@Override
public void accept(Disposable disposable) throws Exception {
Log.d(TAG, "2、doOnSubscribe2:" + Thread.currentThread().getName());
}
}).subscribeOn(Schedulers.io())//S3、subscribeOn切換訂閱線程, io操作的線程
.observeOn(Schedulers.io())//O1、observeOn處理數據流方向, io操作的線程
.flatMap(new Function<Integer, ObservableSource<Integer>>() {//flatMap:數據流的操作符,主要是對數據處理
@Override
public ObservableSource<Integer> apply(Integer integer) throws Exception {
Log.d(TAG,"6、flatMap:" + Thread.currentThread().getName());
return Observable.fromArray(integer);
}
}).observeOn(AndroidSchedulers.mainThread())//O2、observeOn處理數據流方向, Android的主線程
//調用subscribe發起訂閱
.subscribe(new Observer<Integer>() {
private Disposable mDisposable;//Disposable用於解除訂閱
@Override
public void onSubscribe(Disposable d) {
//發起訂閱,向上走
Log.d(TAG, "1、Observer的subscribe:" + Thread.currentThread().getName());
}
@Override
public void onNext(Integer bytes) {
//執行結束
Log.d(TAG, "7、Observer的onNext:" + Thread.currentThread().getName());
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "Observer的onError:" + Thread.currentThread().getName());
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete:" + Thread.currentThread().getName());
}
});
運行效果:
現在我們來講解一下吧:
理解RxJava的操作方向:
- 訂閱,向上走的一個過程
- 數據流,向下走的一個過程數據流,向下走的一個過程
務必記住這幾點:
訂閱的操作符:create丶doOnSubscribe
數據流的操作符:map丶flatMap丶過濾等主要是對數據處理的操作符
走之前記住一句話:subscribeOn切換訂閱線程,observeOn處理數據流方向
1:當我們調用了subscribe的發起訂閱
2:向上走,我只需要關心subscribeOn和訂閱的操作符
3:向下走,我只需要關心observeOn和數據流的操作符
發起訂閱,即流程的起始點:代碼中.subscribe(new Observer<Integer>() { @Override public void onSubscribe(Disposable d) { //發起訂閱,向上走 }...)
這裏是發起訂閱,起始點。
1、開始,發起訂閱:
當前線程狀態(main線程)
訂閱,向上走
經過第一個操作符observeOn,是控制數據流線程的,跳過
經過flatMap處理數據流的操作符,跳過
經過observeOn跳過
經過subscribeOn,將線程切換到IO線程,現在訂閱處於IO線程
經過doOnSubscribe,執行裏面代碼,在IO線程中執行 輸出:doOnSubscribe2:RxCachedThreadScheduler-1
經過subscribeOn,將線程切換到main線程,現在訂閱處於main線程
經過doOnSubscribe,執行裏面代碼,在main線程中執行 輸出:doOnSubscribe1:main
經過map方法,處理數據流的方法,跳過
經過subscribeOn,將線程切換到IO線程,現在訂閱處於IO線程
經過create方法,在IO線程中執行 輸出:create:RxCachedThreadScheduler-1
訂閱完成,開始發射數據 注意:從上面結束我們知道,當前處於IO線程哦
2、當前線程狀態(IO線程):發射數據
發射數據,向下走
經過subscribeOn跳過
經過map,在IO線程中執行 輸出:map1:RxCachedThreadScheduler-1
經過doOnSubscribe跳過
經過subscribeOn跳過
經過doOnSubscribe跳過
經過subscribeOn跳過
經過observeOn,將線程切換到IO線程
經過flatMap執行,在IO線程執行 輸出:flatMap:RxCachedThreadScheduler-2
經過observeOn,將線程切換到main線程
結束執行onNext方法,在main線程輸出:執行完畢:main
三、RxJava+OkHttp
實現的效果:點擊按鈕,獲取網絡圖片並加載到界面上。
1、使用OkHttp獲取網絡圖片工具類
專門寫一個工具類DownLoadUtils
來單獨處理使用OkHttp獲取網絡圖片:
public class DownLoadUtils {
private OkHttpClient client;
public DownLoadUtils(){
client = new OkHttpClient();
}
public Observable<byte[]> downLoadImage(String path){
return Observable.create(new ObservableOnSubscribe<byte[]>() {
@Override
public void subscribe(ObservableEmitter<byte[]> emitter) throws Exception {
if(!emitter.isDisposed()){//isDisposed()查詢是否解除訂閱 true 代表 已經解除訂閱
//訪問網絡操作
Request request = new Request.Builder().url(path).build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
emitter.onError(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if(response.isSuccessful()){
byte[] data = response.body().bytes();
if(data != null){
emitter.onNext(data);
}
}
emitter.onComplete();
}
});
}
}
});
}
}
傳過來網絡圖片地址,初始化被觀察者Observable.create),沒有解除訂閱的話,就進行訪問網絡操作。
網絡請求成功則把獲取到的數據傳遞給ObservableEmitter
,使用emitter.onNext(data)
;失敗了則把錯誤傳給它emitter.onError(e);
。
2、活動使用
圖片地址private String PATH = "http://pic32.nipic.com/20130829/12906030_124355855000_2.png";
,就是在百度圖片上隨便找的。
private DownLoadUtils utils;//下載圖片工具類
點擊按鈕後執行的事件:
//使用HTTP協議獲取數據
//subscribeOn(Schedulers.io()):I/O操作線程,通常用於網絡,讀寫文件等io密集型的操作
//observeOn(AndroidSchedulers.mainThread()):Android主線程
utils.downLoadImage(PATH).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<byte[]>() {
private Disposable mDisposable;//Disposable用於解除訂閱
@Override
public void onSubscribe(Disposable d) {
//訂閱
mDisposable = d;
}
@Override
public void onNext(byte[] bytes) {
//更新界面
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes,0,bytes.length);
imageView.setImageBitmap(bitmap);
//判斷mDisposable.isDisposed()如果解除了則不需要處理
}
@Override
public void onError(Throwable e) {
showToast("報錯"+e.getMessage());
mDisposable.dispose();//主動解除訂閱
}
@Override
public void onComplete() {
showToast("完成");
mDisposable.dispose();//主動解除訂閱
}
});
到了這裏RxJava的基礎使用和基本流程算應該能理解了,接下來就是各種操作符啦,可以看看這個系列,它主要是講解多種操作符這可能是最好的RxJava 2.x 教程(完結版) - 簡書 或者看官方講解。