工作需要,剛好在學(xué)習(xí) RxJava網(wǎng)絡(luò)請(qǐng)求框架,網(wǎng)上搜了一些 關(guān)于RxJava 的教程,但都并不是很好理解,所幸最后找到了幾篇有助于初學(xué)者了解 RxJava 的文章,于是結(jié)合自己的理解,重新整理成一篇發(fā)給大家,希望通過(guò)我的咀嚼,能夠幫助大家更快的了解和上手 RxJava,話(huà)不多說(shuō),進(jìn)入正文吧!
專(zhuān)注于為中小企業(yè)提供成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)興安免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了超過(guò)千家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
1.什么是RxJava
? Rx是Reactive Extensions的簡(jiǎn)寫(xiě),翻譯為響應(yīng)的擴(kuò)展。也就是通過(guò)由一方發(fā)出信息,另一方響應(yīng)信息并作出處理的核心框架代碼。
? 該框架由微軟的架構(gòu)師Erik Meijer領(lǐng)導(dǎo)的團(tuán)隊(duì)開(kāi)發(fā),并在2012年11月開(kāi)源。
? Rx庫(kù)支持.NET、JavaScript和C++等,現(xiàn)在已經(jīng)支持幾乎全部的流行編程語(yǔ)言了。
? Rx的大部分語(yǔ)言庫(kù)由ReactiveX這個(gè)組織負(fù)責(zé)維護(hù),比較流行的有RxJava/RxJS/Rx.NET,社區(qū)網(wǎng)站是 reactivex.io。
? RxJava作為一個(gè)流行的框架,其源碼依托在GitHub,除了支持RxJava,針對(duì)安卓系統(tǒng)也除了一個(gè)支持框架RxAndroid
2.RxJava簡(jiǎn)化代碼
一般我們?cè)诎沧宽?xiàng)目中,如果想從后臺(tái)獲取數(shù)據(jù)并刷新界面,代碼大概如下,下面我們來(lái)看一個(gè)例子:
new Thread() {@Override
br/>@Override
super.run();
for (File folder : folders) {
File[] files = folder.listFiles();
for (File file : files) {
if (file.getName().endsWith(".png")) {
final Bitmap bitmap = getBitmapFromFile(file);
getActivity().runOnUiThread(new Runnable() {@Override
br/>@Override
imageCollectorView.addImage(bitmap);
}
});
}
}
}
}
}.start();
上面的代碼經(jīng)過(guò)多層嵌套后 可讀性太差了!如果你用了RxJava 可以這樣寫(xiě):
Observable.from(folders)
.flatMap(new Func1
br/>@Override
call(File file) {
return Observable.from(file.listFiles());
}
})
.filter(new Func1
br/>@Override
return file.getName().endsWith(".png");
}
})
.map(new Func1
br/>@Override
return getBitmapFromFile(file);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1
br/>@Override
imageCollectorView.addImage(bitmap);
}
});
這樣寫(xiě)的好處就是減少層次嵌套 提高了代碼的可讀性,除了簡(jiǎn)化代碼,RxJava還可以為每個(gè)方法提供特定的運(yùn)行線(xiàn)程。
3.引入框架
目前RxJava已經(jīng)升級(jí)為2.0版本,但為了能夠更好的理解RxJava,我們可以從1.0版本開(kāi)始學(xué)習(xí)。也為了讓我們的安卓項(xiàng)目能夠更好的使用RxJava,可以在項(xiàng)目中引入gradle腳本依賴(lài):
compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.1.6'
現(xiàn)在 我們的項(xiàng)目已經(jīng)支持RxJava的功能了。
4.響應(yīng)式的核心
所謂的響應(yīng)式,無(wú)非就是存在這樣的2個(gè)部分,一部分負(fù)責(zé)發(fā)送事件/消息,另一部分負(fù)責(zé)響應(yīng)事件/消息。
以前如果我們想看新聞,一般需要通過(guò)看報(bào)紙。比如,你對(duì)某個(gè)報(bào)刊雜志比較感興趣,那么你首先要做3件事:
訂閱(也就是 觀(guān)察者&被觀(guān)察者之間要相互關(guān)聯(lián) 以便被觀(guān)察的對(duì)象一變化 就會(huì)馬上通知觀(guān)察該事件的對(duì)象)
上面示例的演示代碼如下:
//1.創(chuàng)建被觀(guān)察者
Observable
Observable.create(new Observable.OnSubscribe
br/>@Override
subscriber) {
//4.開(kāi)始發(fā)送事件
//事件有3個(gè)類(lèi)型 分別是onNext() onCompleted() onError()
//onCompleted() onError() 一般都是用來(lái)通知觀(guān)察者 事件發(fā)送完畢了,兩者只取其一。
subscriber.onNext("Hello Android !");
subscriber.onNext("Hello Java !");
subscriber.onNext("Hello C !");
subscriber.onCompleted();
}
});
//2.創(chuàng)建觀(guān)察者
Subscriber
br/>@Override
Log.i(TAG, "onCompleted ");
}
@Override
public void onError(Throwable e) {
Log.i(TAG, "onError: "+e.getLocalizedMessage());
}
@Override
public void onNext(String s) {
Log.i(TAG, "onNext: "+s);
}
};
//3.訂閱
observable.subscribe(subscriber);
輸出如下:
com.m520it.rxjava I/IT520: onNext: Hello Android !
com.m520it.rxjava I/IT520: onNext: Hello Java !
com.m520it.rxjava I/IT520: onNext: Hello C !
com.m520it.rxjava I/IT520: onCompleted
代碼運(yùn)行的原理
? 上面的代碼中,當(dāng)觀(guān)察者subscriber訂閱了被觀(guān)察者observable之后,系統(tǒng)會(huì)自動(dòng)回調(diào)observable對(duì)象內(nèi)部的call()。
? 在observable的call()方法實(shí)體中,發(fā)送了如onNext/onCompleted/onError事件后。
? 接著subscriber就能回調(diào)到到對(duì)應(yīng)的方法。
5.被觀(guān)察者變種
普通的Observable發(fā)送需要三個(gè)方法onNext, onError, onCompleted,而Single作為Observable的變種,只需要兩個(gè)方法:
? onSuccess - Single發(fā)射單個(gè)的值到這個(gè)方法
? onError - 如果無(wú)法發(fā)射需要的值,Single發(fā)射一個(gè)Throwable對(duì)象到這個(gè)方法
Single只會(huì)調(diào)用這兩個(gè)方法中的一個(gè),而且只會(huì)調(diào)用一次,調(diào)用了任何一個(gè)方法之后,訂閱關(guān)系終止。
final Single
br/>@Override
singleSubscriber) {
//先調(diào)用onNext() 最后調(diào)用onCompleted()
//singleSubscriber.onSuccess("Hello Android !");
//只調(diào)用onError();
singleSubscriber.onError(new NullPointerException("mock Exception !"));
}
});
Observer
br/>@Override
Log.i(TAG, "onCompleted ");
}
@Override
public void onError(Throwable e) {
Log.i(TAG, "onError: "+e.getLocalizedMessage());
}
@Override
public void onNext(String s) {
Log.i(TAG, "onNext: "+s);
}
};
single.subscribe(observer);
6.觀(guān)察者變種
Observer觀(guān)察者對(duì)象,上面我們用Subscriber對(duì)象代替。因?yàn)樵搶?duì)象本身就是繼承了Observer。
該對(duì)象實(shí)現(xiàn)了onNext()&onCompleted()&onError()事件,我們?nèi)绻麑?duì)哪個(gè)事件比較關(guān)心,只需要實(shí)現(xiàn)對(duì)應(yīng)的方法即可,代碼如下:
//創(chuàng)建觀(guān)察者
Subscriber
br/>@Override
Log.i(TAG, "onCompleted ");
}
@Override
public void onError(Throwable e) {
Log.i(TAG, "onError: "+e.getLocalizedMessage());
}
@Override
public void onNext(String s) {
Log.i(TAG, "onNext: "+s);
}
};
//訂閱
observable.subscribe(subscriber);
上面的代碼中,如果你只關(guān)心onNext()事件,但卻不得不實(shí)現(xiàn)onCompleted()&onError()事件.這樣的代碼就顯得很臃腫。鑒于這種需求,RxJava框架在訂閱方面做了特定的調(diào)整,代碼如下:
//為指定的onNext事件創(chuàng)建獨(dú)立的接口
Action1
br/>@Override
Log.i(TAG, "call: "+s);
}
};
//訂閱
observable.subscribe(onNextAction);
不知道大家注意到?jīng)]有,subscribe()訂閱的不再是觀(guān)察者,而是特定的onNext接口對(duì)象。類(lèi)似的函數(shù)如下,我們可以根據(jù)需要實(shí)現(xiàn)對(duì)應(yīng)的訂閱:
public Subscription subscribe(final Observer observer)
public Subscription subscribe(final Action1 onNext)
public Subscription subscribe(final Action1 onNext, Action1 onError)
public Subscription subscribe(final Action1 onNext, Action1 onError, Action0 onCompleted)
這里還有一個(gè)forEach函數(shù)有類(lèi)似的功能:
public void forEach(final Action1 onNext)
public void forEach(final Action1 onNext, Action1 onError)
public void forEach(final Action1 onNext, Action1 onError, Action0 onComplete)
##7.Subject變種
上面2節(jié)中既介紹了被觀(guān)察者變種,又介紹了觀(guān)察者變種,這里再介紹一種雌雄同體的對(duì)象(既作為被觀(guān)察者使用,也可以作為觀(guān)察者)。
針對(duì)不同的場(chǎng)景一共有四種類(lèi)型的Subject。他們并不是在所有的實(shí)現(xiàn)中全部都存在。
###AsyncSubject
一個(gè)AsyncSubject只在原始Observable完成后,發(fā)射來(lái)自原始Observable的最后一個(gè)值。它會(huì)把這最后一個(gè)值發(fā)射給任何后續(xù)的觀(guān)察者。
以下貼出代碼:
//創(chuàng)建被觀(guān)察者final AsyncSubject
Subscriber
br/>@Override
Log.i(TAG, "onCompleted");
}
@Override
public void onError(Throwable e) {
Log.i(TAG, "onError");
}
@Override
public void onNext(String s) {
Log.i(TAG, "s:" + s);
}
};//訂閱事件
subject.subscribe(subscriber);//被觀(guān)察者發(fā)出事件 如果調(diào)用onCompleted(),onNext()則會(huì)打印最后一個(gè)事件;如果沒(méi)有,onNext()則不打印任何事件。
subject.onNext("Hello Android ");
subject.onNext("Hello Java ");
subject.onCompleted();
輸出:
s:Hello Java onCompleted
然而,如果原始的Observable因?yàn)榘l(fā)生了錯(cuò)誤而終止,AsyncSubject將不會(huì)發(fā)射任何數(shù)據(jù),只是簡(jiǎn)單的向前傳遞這個(gè)錯(cuò)誤通知。
上面的觀(guān)察者被觀(guān)察者代碼相同,現(xiàn)在發(fā)出一系列信號(hào),并在最后發(fā)出異常 代碼如下:
subject.onNext("Hello Android ");
subject.onNext("Hello Java ");//因?yàn)榘l(fā)送了異常 所以onNext()無(wú)法被打印
subject.onError(null);
###BehaviorSubject
當(dāng)觀(guān)察者訂閱BehaviorSubject時(shí),他會(huì)將訂閱前最后一次發(fā)送的事件和訂閱后的所有發(fā)送事件都打印出來(lái),如果訂閱前無(wú)發(fā)送事件,則會(huì)默認(rèn)接收構(gòu)造器create(T)里面的對(duì)象和訂閱后的所有事件,代碼如下:
BehaviorSubject subject=BehaviorSubject.create("NROMAL");
Subscriber subscriber = new Subscriber() {@Override
br/>@Override
Log.i(TAG, "onCompleted");
}
@Override
public void onError(Throwable e) {
Log.i(TAG, "onError");
}
@Override
public void onNext(Object o) {
Log.i(TAG, "onNext: " + o);
}
};
//subject.onNext("Hello Android !");//subject.onNext("Hello Java !");//subject.onNext("Hello C !");//這里開(kāi)始訂閱 如果上面的3個(gè)注釋沒(méi)去掉,則Hello C的事件和訂閱后面的事件生效//如果上面的三個(gè)注釋去掉 則打印構(gòu)造器NORMAL事件生效后和訂閱后面的事件生效
subject.subscribe(subscriber);
subject.onNext("Hello CPP !");
subject.onNext("Hello IOS !");
PublishSubject
PublishSubject只會(huì)把在訂閱發(fā)生的時(shí)間點(diǎn)之后來(lái)自原始Observable的數(shù)據(jù)發(fā)射給觀(guān)察者。
需要注意的是,PublishSubject可能會(huì)一創(chuàng)建完成就立刻開(kāi)始發(fā)射數(shù)據(jù),因此這里有一個(gè)風(fēng)險(xiǎn):在Subject被創(chuàng)建后到有觀(guān)察者訂閱它之前這個(gè)時(shí)間段內(nèi),一個(gè)或多個(gè)數(shù)據(jù)可能會(huì)丟失。
代碼如下:
PublishSubject subject= PublishSubject.create();
Action1
@Override
public void call(String s) {
Log.i(TAG, "onNextAction1 call: "+s);
}
};
Action1
@Override
public void call(String s) {
Log.i(TAG, "onNextAction2 call: "+s);
}
};
subject.onNext("Hello Android !");
subject.subscribe(onNextAction1);
subject.onNext("Hello Java !");
subject.subscribe(onNextAction2);
subject.onNext("Hello IOS !");
輸出如下:
onNextAction1 call: Hello Java !
onNextAction1 call: Hello IOS !
onNextAction2 call: Hello IOS !
ReplaySubject
ReplaySubject會(huì)發(fā)射所有來(lái)自原始Observable的數(shù)據(jù)給觀(guān)察者,無(wú)論它們是何時(shí)訂閱的。
代碼如下:
ReplaySubject subject= ReplaySubject.create();
Action1
@Override
public void call(String s) {
Log.i(TAG, "onNextAction1 call: "+s);
}
};
Action1
@Override
public void call(String s) {
Log.i(TAG, "onNextAction2 call: "+s);
}
};
subject.onNext("Hello Android !");
subject.subscribe(onNextAction1);
subject.onNext("Hello Java !");
subject.subscribe(onNextAction2);
subject.onNext("Hello IOS !");
輸出如下:
onNextAction1 call: Hello Android !
onNextAction1 call: Hello Java !
onNextAction2 call: Hello Android !
onNextAction2 call: Hello Java !
onNextAction1 call: Hello IOS !
onNextAction2 call: Hello IOS !
###Subject總結(jié)
AsyncSubject無(wú)論何時(shí)訂閱 只會(huì)接收最后一次onNext()事件,如果最后出現(xiàn)異常,則不會(huì)打印任何onNext()
BehaviorSubject會(huì)從訂閱前最后一次oNext()開(kāi)始打印直至結(jié)束。如果訂閱前無(wú)調(diào)用onNext(),則調(diào)用默認(rèn)creat(T)傳入的對(duì)象。如果異常后才調(diào)用,則不打印onNext()
PublishSubject只會(huì)打印訂閱后的任何事件。
ReplaySubject無(wú)論訂閱在何時(shí)都會(huì)調(diào)用發(fā)送的事件。
以上就是我了解的關(guān)于RxJava的入門(mén)相關(guān)知識(shí),如果你還有其他相關(guān)的干貨分享,還望補(bǔ)充。