Rxjava 源于ReactiveX(Reactive Extensions),Rx是一個變成模型,目標是提供一致的編程接口,幫助開發者方便的處理異步數據流,許多流行的變成語言都有Rx庫。Rx擴展了觀察者模式,用于支持數據和事件序列,添加了一些操作符,他人你可以聲明式的組合這些序列,而無需關注底層的實現(線程、同步、線程安全、并發)。
Rxjava優勢就是使得代碼更簡潔,而且隨著程序邏輯變得越來越復雜,它依然能夠保持簡潔。
擴展的觀察者
Observable(被觀察者)、Observer(觀察者)、subscribe(訂閱),Observable和Observer通過subscribe方法實現訂閱關系。Observable在需要的時候發出事件來通知Observer。
與傳統的觀察者模式不同,除了定義了普通的回調事件onNext(),還定義的兩個特殊的事件onCompleted()和onError()。
- onCompleted:事件隊列完結,Rxjava把所有事件看做一個隊列,并規定,當不會再有新的onNext事件觸發時,需要觸發onCompleted
- onError:事件隊列異常,在時間處理過程中出現異常時觸發onError,同時隊列終止,不允許再有事件發出
- onCompleted和onError有且只有一個,并且是事件序列的最后一個
基本實現
創建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 還內置了一個實現了 Observer 的抽象類:Subscriber,Subscriber 對 Observer 接口進行了一些擴展,但他們的基本使用方式是完全一樣的。
與Observer 的主要區別:
- onStart:這是Subscriber 新增的方法,會在subscribe里,事件還未發送前調用,它總是在subscribe所發生的線程被調用
2、unsubscribe:這是Subscriber 新增的方法,用于取消訂閱,這個方法被調用后,Subscriber將不再接收事件。Observable 會持有 Subscriber 的引用,這個引用如果不能及時被釋放,將有內存泄露的風險。所以最好保持一個原則:要在不再使用的時候盡快在合適的地方(例如 onPause() onStop() 等方法中)調用 unsubscribe() 來解除引用關系,以避免內存泄露的發生。
Subscription clickSubscribe = RxView.clicks(findViewById(R.id.bt))
.throttleFirst(1, TimeUnit.SECONDS)
.doOnUnsubscribe(new Action0() {
@Override
public void call() {
Log.e(TAG, "clicks->doOnUnsubscribe");
}
})
.subscribe(new Action1<Void>() {
@Override
public void call(Void aVoid) {
methd6();
}
});
//維護相關的資源引用
subscriptions.add(clickSubscribe);
@Override
protected void onDestroy() {
for (Subscription s : subscriptions) {
if (!s.isUnsubscribed()) {
s.unsubscribe();
Log.e(TAG, "onDestroy: 取消訂閱!");
}
}
super.onDestroy();
}
創建Observable,定義被觀察者,決定什么時候出發事件以及觸發怎么樣的事件
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的操作符
- create(OnSubscribe)
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();
}
});
- just(T...): 將傳入的參數依次發送出來。
Observable observable = Observable.just("Hello", "Hi", "Aloha");
// 將會依次調用:
// onNext("Hello");
// onNext("Hi");
// onNext("Aloha");
// onCompleted();
- from(T[]) / from(Iterable<? extends T>) : 將傳入的數組或 Iterable 拆分成具體對象后,依次發送出來。
String[] words = {"Hello", "Hi", "Aloha"};
Observable observable = Observable.from(words);
// 將會依次調用:
// onNext("Hello");
// onNext("Hi");
// onNext("Aloha");
// onCompleted();
- empty 創建一個什么都不做直接通知完成的Observable
- error 創建一個什么都不做直接通知錯誤的Observable
- never 創建一個什么都不做的Observable
Observable observable1=Observable.empty();//直接調用onCompleted。
Observable observable2=Observable.error(new RuntimeException());//直接調用onError。這里可以自定義異常
Observable observable3=Observable.never();//啥都不做
- timer 創建一個在給定的延時之后發射數據項為0的Observable<Long>
Observable.timer(1000,TimeUnit.MILLISECONDS)
.subscribe(new Action1<Long>() {
@Override
public void call(Long aLong) {
Log.d("JG",aLong.toString()); // 0
}
});
- interval 創建一個按照給定的時間間隔發射從0開始的整數序列的Observable<Long>
Observable.interval(1, TimeUnit.SECONDS)
.subscribe(new Action1<Long>() {
@Override
public void call(Long aLong) {
//每隔1秒發送數據項,從0開始計數
//0,1,2,3....
}
});
- range 創建一個發射指定范圍的整數序列的Observable<Integer>
Observable.range(2,5).subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
Log.d("JG",integer.toString());// 2,3,4,5,6 從2開始發射5個數據
}
});
- defer 只有當訂閱者訂閱才創建Observable,為每個訂閱創建一個新的Observable。內部通過OnSubscribeDefer在訂閱時調用Func0創建Observable。
Observable.defer(new Func0<Observable<String>>() {
@Override
public Observable<String> call() {
return Observable.just("hello");
}
}).subscribe(new Action1<String>() {
@Override
public void call(String s) {
Log.d("JG",s);
}
});
合并操作符
- concat: 按順序連接多個Observables。需要注意的是Observable.concat(a,b)等價于a.concatWith(b)。
Observable<Integer> observable1=Observable.just(1,2,3,4);
Observable<Integer> observable2=Observable.just(4,5,6);
Observable.concat(observable1,observable2)
.subscribe(item->Log.d("JG",item.toString()));//1,2,3,4,4,5,6
- startWith: 在數據序列的開頭增加一項數據。startWith的內部也是調用了concat
Observable.just(1,2,3,4,5)
.startWith(6,7,8)
.subscribe(item->Log.d("JG",item.toString()));//6,7,8,1,2,3,4,5
- merge 將多個Observable合并為一個。不同于concat,merge不是按照添加順序連接,而是按照時間線來連接。其中mergeDelayError將異常延遲到其它沒有錯誤的Observable發送完畢后才發射。而merge則是一遇到異常將停止發射數據,發送onError通知。
- zip: 使用一個函數組合多個Observable發射的數據集合,然后再發射這個結果。如果多個Observable發射的數據量不一樣,則以最少的Observable為標準進行壓合。內部通過OperatorZip進行壓合。
Observable<Integer> observable1=Observable.just(1,2,3,4);
Observable<Integer> observable2=Observable.just(4,5,6);
Observable.zip(observable1, observable2, new Func2<Integer, Integer, String>() {
@Override
public String call(Integer item1, Integer item2) {
return item1+"and"+item2;
}
})
.subscribe(item->Log.d("JG",item)); //1and4,2and5,3and6
- combineLatest 當兩個Observables中的任何一個發射了一個數據時,通過一個指定的函數組合每個Observable發射的最新數據(一共兩個數據),然后發射這個函數的結果。類似于zip,但是,不同的是zip只有在每個Observable都發射了數據才工作,而combineLatest任何一個發射了數據都可以工作,每次與另一個Observable最近的數據壓合。
過濾操作
- filter 過濾數據。內部通過OnSubscribeFilter過濾數據。
Observable.just(3,4,5,6)
.filter(new Func1<Integer, Boolean>() {
@Override
public Boolean call(Integer integer) {
return integer>4;
}
})
.subscribe(item->Log.d("JG",item.toString())); //5,6
還有ofType、take、takeLast、throttleFirst、timeout等
條件/布爾操作
- all 判斷所有的數據項是否滿足某個條件,內部通過OperatorAll實現。
Observable.just(2,3,4,5)
.all(new Func1<Integer, Boolean>() {
@Override
public Boolean call(Integer integer) {
return integer>3;
}
})
.subscribe(new Action1<Boolean>() {
@Override
public void call(Boolean aBoolean) {
Log.d("JG",aBoolean.toString()); //false
}
})
;
還有exists、contains、isEmpty等
聚合操作
- reduce: 對序列使用reduce()函數并發射最終的結果,內部使用OnSubscribeReduce實現。
Observable.just(2,3,4,5)
.reduce(new Func2<Integer, Integer, Integer>() {
@Override
public Integer call(Integer sum, Integer item) {
return sum+item;
}
})
.subscribe(integer -> Log.d("JG",integer.toString()));//14
還有collect、count/countLong
轉換操作
- toList 收集原始Observable發射的所有數據到一個列表,然后返回這個列表
Observable.just(2,3,4,5)
.toList()
.subscribe(new Action1<List<Integer>>() {
@Override
public void call(List<Integer> integers) {
}
});
還有toSortedList、toMap、toMultiMap
變換操作
- map 對Observable發射的每一項數據都應用一個函數來變換。
Observable.just(6,2,3,4,5)
.map(integer -> "item:"+integer)
.subscribe(s -> Log.d("JG",s));//item:6,item:2....
還有cast、flatMap、flatMapIterable、concatMap、switchMap等
錯誤處理/重試機制
- onErrorResumeNext 當原始Observable在遇到錯誤時,使用備用Observable。
Observable.just(1,"2",3)
.cast(Integer.class)
.onErrorResumeNext(Observable.just(1,2,3))
.subscribe(integer -> Log.d("JG",integer.toString())) //1,2,3
;
- onExceptionResumeNext 當原始Observable在遇到異常時,使用備用的Observable。與onErrorResumeNext類似,區別在于onErrorResumeNext可以處理所有的錯誤,onExceptionResumeNext只能處理異常。
- onErrorReturn 當原始Observable在遇到錯誤時發射一個特定的數據。
Observable.just(1,"2",3)
.cast(Integer.class)
.onErrorReturn(new Func1<Throwable, Integer>() {
@Override
public Integer call(Throwable throwable) {
return 4;
}
}).subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
Log.d("JG",integer.toString());1,4
}
});
- retry: 當原始Observable在遇到錯誤時進行重試。
Observable.just(1,"2",3)
.cast(Integer.class)
.retry(3)
.subscribe(integer -> Log.d("JG",integer.toString()),throwable -> Log.d("JG","onError"))
;//1,1,1,1,onError
- retryWhen 當原始Observable在遇到錯誤,將錯誤傳遞給另一個Observable來決定是否要重新訂閱這個Observable,內部調用的是retry。
Observable.just(1,"2",3)
.cast(Integer.class)
.retryWhen(new Func1<Observable<? extends Throwable>, Observable<Long>>() {
@Override
public Observable<Long> call(Observable<? extends Throwable> observable) {
return Observable.timer(1, TimeUnit.SECONDS);
}
})
.subscribe(integer -> Log.d("JG",integer.toString()),throwable -> Log.d("JG","onError"));
//1,1
還有一些操作符具體還是看RxJava操作符大全這個文章吧
線程控制
在不指定線程的情況下, RxJava 遵循的是線程不變的原則,即:在哪個線程調用 subscribe(),就在哪個線程生產事件;在哪個線程生產事件,就在哪個線程消費事件。如果需要切換線程,就需要用到 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。
- 另外, Android 還有一個專用的 AndroidSchedulers.mainThread(),它指定的操作將在 Android 主線程運行。
使用 subscribeOn() 和 observeOn() 兩個方法來對線程進行控制
- subscribeOn(): 指定 subscribe() 所發生的線程,即 Observable.OnSubscribe 被激活時所處的線程。或者叫做事件產生的線程。
- observeOn(): 指定 Subscriber 所運行在的線程。或者叫做事件消費的線程。
observeOn() 指定的是 Subscriber 的線程,而這個 Subscriber 并不是(嚴格說應該為『不一定是』,但這里不妨理解為『不是』)subscribe() 參數中的 Subscriber ,而是 observeOn() 執行時的當前 Observable 所對應的 Subscriber ,即它的直接下級 Subscriber 。換句話說,observeOn() 指定的是它之后的操作所在的線程。因此如果有多次切換線程的需求,只要在每個想要切換線程的位置調用一次 observeOn() 即可。
Observable.just(1, 2, 3, 4) // IO 線程,由 subscribeOn() 指定
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.newThread())
.map(mapOperator) // 新線程,由 observeOn() 指定
.observeOn(Schedulers.io())
.map(mapOperator2) // IO 線程,由 observeOn() 指定
.observeOn(AndroidSchedulers.mainThread)
.subscribe(subscriber); // Android 主線程,由 observeOn() 指定
subscribeOn() 的位置放在哪里都可以,但它是只能調用一次的。
doOnSubscribe()它和 Subscriber.onStart() 同樣是在 subscribe() 調用后而且在事件發送前執行,但區別在于它可以指定線程。默認情況下, doOnSubscribe() 執行在 subscribe() 發生的線程;而如果在 doOnSubscribe() 之后有 subscribeOn() 的話,它將執行在離它最近的 subscribeOn() 所指定的線程。
Observable.create(onSubscribe)
.subscribeOn(Schedulers.io())
.doOnSubscribe(new Action0() {
@Override
public void call() {
progressBar.setVisibility(View.VISIBLE); // 需要在主線程執行
}
})
.subscribeOn(AndroidSchedulers.mainThread()) // 指定主線程
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);