Android RxJava詳解
這兩天閑來(lái)無(wú)事就想著學(xué)習(xí)一下當(dāng)前比較流行的框架揉燃,看到網(wǎng)上很多大神推薦RxJava
和Retrofit的混合使用,就想著自己也學(xué)習(xí)一下封裝一下植酥,于是就查閱了很多文章總是感
覺(jué)缺少點(diǎn)什么依啰,直到碰到了他的文章(鏈接在文章末尾)才有一種恍然大悟的感覺(jué)乌妙,在此做
一個(gè)總結(jié)袄膏。
響應(yīng)式代碼的基本組成部分是Observables和Subscribers(事實(shí)上Observer才是最小的構(gòu)建塊布轿,但實(shí)踐中使用最多的是Subscriber奠蹬,因?yàn)镾ubscriber才是和Observables的對(duì)應(yīng)的朝聋。)。Observable發(fā)送消息囤躁,而Subscriber則用于消費(fèi)消息冀痕。
-
RxJava 基本概念
- Observable (可觀察者,即被觀察者)
- Observer (觀察者)
- subscribe (訂閱)狸演、事件
- Scheduler 調(diào)度器言蛇,相當(dāng)于線程控制器
Observable 和Observer 通過(guò) subscribe() 方法實(shí)現(xiàn)訂閱關(guān)系,從而 Observable 可以在需要的時(shí)候發(fā)出事件來(lái)通知 Observer宵距。
-
RxJava的實(shí)現(xiàn)流程
-
創(chuàng)建Observer(觀察者)
Observer 即觀察者,它決定事件觸發(fā)的時(shí)候?qū)⒂性鯓拥男袨?RxJava中的Observer的實(shí)現(xiàn)方式:
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!"); } };
Subscriber是對(duì)Observe的抽象類腊尚,RxJava對(duì)其實(shí)現(xiàn)了一些擴(kuò)展,但是使用方式基本一致:
Subscriber<String> subscriber = new Subscriber<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!"); } };
Observer也總是會(huì)先被轉(zhuǎn)換成一個(gè)Subscriber再使用,不同的是Subscriber中又增加了兩個(gè)方法onStart() 和 UnSubscriber();
-
創(chuàng)建Observable(被觀察者)
Observable即被觀察者,它決定什么時(shí)候觸發(fā)事件以及觸發(fā)怎樣的事件满哪。RxJava 使用create()方法來(lái)創(chuàng)建一個(gè)Observable,并為它定義事件觸發(fā)規(guī)則:
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(); } });
這里傳入了一個(gè)OnSubscribe對(duì)象作為參數(shù)婿斥。OnSubscribe會(huì)被存儲(chǔ)在返回的 Observable對(duì)象中,它的作用相當(dāng)于一個(gè)計(jì)劃表哨鸭,當(dāng)Observable被訂閱的時(shí)候民宿,OnSubscribe的call()方法會(huì)自動(dòng)被調(diào)用,事件序列就會(huì)依照設(shè)定依次觸發(fā)(對(duì)于上面的代碼像鸡,就是觀察者Subscriber 將會(huì)被調(diào)用三次 onNext() 和一次 onCompleted())活鹰。這樣,由被觀察者調(diào)用了觀察者的回調(diào)方法,就實(shí)現(xiàn)了由被觀察者向觀察者的事件傳遞.
-
創(chuàng)建Subscribe(訂閱)
創(chuàng)建了 Observable 和 Observer 之后华望,再用 subscribe() 方法將它們聯(lián)結(jié)起來(lái):
observable.subscribe(observer); // 或者: observable.subscribe(subscriber);
-
以上的代碼也可以這么寫(xiě):
Observable.create(new OnSubscribe<Drawable>() {
@Override
public void call(Subscriber<? super Drawable> subscriber) {
Drawable drawable = getTheme().getDrawable(drawableRes));
subscriber.onNext(drawable);
subscriber.onCompleted();
}
}).subscribe(new Observer<Drawable>() {
@Override
public void onNext(Drawable drawable) {
imageView.setImageDrawable(drawable);
}
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
Toast.makeText(activity, "Error!", Toast.LENGTH_SHORT).show();
}
});
-
Scheduler--線程控制
在不指定線程的情況下蕊蝗,RxJava遵循的是線程不變的原則,即:在哪個(gè)線程調(diào)用 subscribe(),就在哪個(gè)線程生產(chǎn)事件赖舟;在哪個(gè)線程生產(chǎn)事件蓬戚,就在哪個(gè)線程消費(fèi)事件。如果需要切換線程宾抓,就需要用到Scheduler(調(diào)度器),下面是Scheduler的API:
- Schedulers.immediate(): 直接在當(dāng)前線程運(yùn)行子漩,相當(dāng)于不指定線程。這是默認(rèn)的 Scheduler石洗。
- Schedulers.newThread(): 總是啟用新線程幢泼,并在新線程執(zhí)行操作。
- Schedulers.io(): I/O 操作(讀寫(xiě)文件讲衫、讀寫(xiě)數(shù)據(jù)庫(kù)缕棵、網(wǎng)絡(luò)信息交互等)所使用的 Scheduler。行為模式和 newThread() 差不多涉兽,區(qū)別在于 io() 的內(nèi)部實(shí)現(xiàn)是是用一個(gè)無(wú)數(shù)量上限的線程池招驴,可以重用空閑的線程,因此多數(shù)情況下 io() 比 newThread() 更有效率枷畏。不要把計(jì)算工作放在 io() 中别厘,可以避免創(chuàng)建不必要的線程。
- Schedulers.computation(): 計(jì)算所使用的 Scheduler拥诡。這個(gè)計(jì)算指的是 CPU 密集型計(jì)算触趴,即不會(huì)被 I/O 等操作限制性能的操作,例如圖形的計(jì)算渴肉。這個(gè) Scheduler 使用的固定的線程池冗懦,大小為 CPU 核數(shù)。不要把 I/O 操作放在 computation() 中宾娜,否則 I/O 操作的等待時(shí)間會(huì)浪費(fèi) CPU批狐。
- Android 還有一個(gè)專用的 AndroidSchedulers.mainThread(),它指定的操作將在 Android 主線程運(yùn)行前塔。
有了這幾個(gè) Scheduler 嚣艇,就可以使用 subscribeOn() 和 observeOn() 兩個(gè)方法來(lái)對(duì)線程進(jìn)行控制了。
subscribeOn(): 指定subscribe()所發(fā)生的線程华弓,即 Observable.OnSubscribe被激活時(shí)所處的線程食零。或者叫做事件產(chǎn)生的線程寂屏。
observeOn(): 指定 Subscriber 所運(yùn)行在的線程贰谣∧嚷В或者叫做事件消費(fèi)的線程。
Demo:
Observable.just(1, 2, 3, 4)
.subscribeOn(Schedulers.io()) // 指定 subscribe() 發(fā)生在 IO 線程
.observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回調(diào)發(fā)生在主線程
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer number) {
Log.d(tag, "number:" + number);
}
});
Operators:RxJava提供了對(duì)事務(wù)序列進(jìn)行變換的功能吱抚,這是RxJava的核心功能之一百宇。變換就是將事件序列中的對(duì)象或整個(gè)序列進(jìn)行加工處理,轉(zhuǎn)換成不同的事件或事件序列秘豹。
-
from操作符可以轉(zhuǎn)換Future携御、Iterable和數(shù)組。對(duì)于Iterable和數(shù)組既绕,產(chǎn)生的Observable會(huì)發(fā)射Iterable或數(shù)組的每一項(xiàng)數(shù)據(jù)啄刹。
Integer[] items = { 0, 1, 2, 3, 4, 5 }; Observable myObservable = Observable.from(items); myObservable.subscribe( new Action1<Integer>() { @Override public void call(Integer item) { System.out.println(item); } }, new Action1<Throwable>() { @Override public void call(Throwable error) { System.out.println("Error encountered: " + error.getMessage()); } }, new Action0() { @Override public void call() { System.out.println("Sequence complete"); } } );
-
Just:Just類似于From,但是From會(huì)將數(shù)組或Iterable的素具取出然后逐個(gè)發(fā)射凄贩,而Just只是簡(jiǎn)單的原樣發(fā)射誓军,將數(shù)組或Iterable當(dāng)做單個(gè)數(shù)據(jù)。
注意:如果你傳遞null給Just疲扎,它會(huì)返回一個(gè)發(fā)射null值的Observable昵时。不要誤認(rèn)為 它會(huì)返回一個(gè)空Observable(完全不發(fā)射任何數(shù)據(jù)的Observable),如果需要空 Observable你應(yīng)該使用Empty操作符评肆。
Observable.just(1, 2, 3) .subscribe(new Subscriber<Integer>() { @Override public void onNext(Integer item) { System.out.println("Next: " + item); } @Override public void onError(Throwable error) { System.err.println("Error: " + error.getMessage()); } @Override public void onCompleted() { System.out.println("Sequence complete."); } });
-
map():Map操作符對(duì)原始Observable發(fā)射的每一項(xiàng)數(shù)據(jù)應(yīng)用一個(gè)你選擇的函數(shù)债查,然后返回一個(gè)發(fā)射這些結(jié)果的Observable
Observable.just("images/logo.png") // 輸入類型 String .map(new Func1<String, Bitmap>() { @Override public Bitmap call(String filePath) { // 參數(shù)類型 String return getBitmapFromPath(filePath); // 返回類型 Bitmap } }) .subscribe(new Action1<Bitmap>() { @Override public void call(Bitmap bitmap) { // 參數(shù)類型 Bitmap showBitmap(bitmap); } });
map() 方法將參數(shù)中的 String 對(duì)象轉(zhuǎn)換成一個(gè) Bitmap 對(duì)象后返回,而在經(jīng)過(guò) map() 方法后瓜挽,事件的參數(shù)類型也由 String轉(zhuǎn)為了 Bitmap。這種直接變換對(duì)象并返回的征绸,是最常見(jiàn)的也最容易理解的變換久橙。不過(guò) RxJava 的變換遠(yuǎn)不止這樣,它不僅可以針對(duì)事件對(duì)象管怠,還可以針對(duì)整個(gè)事件隊(duì)列淆衷,這使得 RxJava 變得非常靈活。
-
flatMap():
Student[] students = ...; Subscriber<Course> subscriber = new Subscriber<Course>() { @Override public void onNext(Course course) { Log.d(tag, course.getName()); } ... }; Observable.from(students) .flatMap(new Func1<Student, Observable<Course>>() { @Override public Observable<Course> call(Student student) { return Observable.from(student.getCourses()); } }) .subscribe(subscriber);
flatMap() 和 map() 有一個(gè)相同點(diǎn):它也是把傳入的參數(shù)轉(zhuǎn)化之后返回另一個(gè)對(duì)象渤弛。但需要注意祝拯,和 map()不同的是, flatMap() 中返回的是個(gè) Observable 對(duì)象她肯,并且這個(gè) Observable 對(duì)象并不是被直接發(fā)送到了 Subscriber 的回調(diào)方法中佳头。 flatMap() 的原理是這樣的:1. 使用傳入的事件對(duì)象創(chuàng)建一個(gè) Observable 對(duì)象;2. 并不發(fā)送這個(gè) Observable, 而是將它激活晴氨,于是它開(kāi)始發(fā)送事件康嘉;3. 每一個(gè)創(chuàng)建出來(lái)的 Observable 發(fā)送的事件,都被匯入同一個(gè) Observable 籽前,而這個(gè) Observable 負(fù)責(zé)將這些事件統(tǒng)一交給 Subscriber 的回調(diào)方法亭珍。這三個(gè)步驟敷钾,把事件拆成了兩級(jí),通過(guò)一組新創(chuàng)建的 Observable 將初始的對(duì)象『鋪平』之后通過(guò)統(tǒng)一路徑分發(fā)了下去肄梨。而這個(gè)『鋪平』就是 flatMap() 所謂的 flat阻荒。
-
throttleFirst():在每次事件觸發(fā)后的一定時(shí)間間隔內(nèi)丟棄新的事件。常用作去抖動(dòng)過(guò)濾众羡,例如按鈕的點(diǎn)擊監(jiān)聽(tīng)器:
RxView.clickEvents(button) //RxBinding代碼 .throttleFirst(500, TimeUnit.MILLISECONDS) //設(shè)置防抖間隔為500ms .subscribe(subscriber);
建議大家多去理解一下RxJava的變換财松,這是個(gè)難點(diǎn)和功能點(diǎn)邑时。