什么是RxJava##
- RxJava 就是異步
- RxJava 的異步實(shí)現(xiàn)睬罗,是通過(guò)一種擴(kuò)展的觀察者模式來(lái)實(shí)現(xiàn)的宿稀。
- 一個(gè)響應(yīng)式編程框架
通過(guò)之前對(duì)RxJava的了解,我們已經(jīng)掌握了RxJava的一些基礎(chǔ)使用方法,下面我們結(jié)合一個(gè)簡(jiǎn)單的Demo,看看如何在Android 開發(fā)中使用RxJava阎毅。
RxAndroid 初體驗(yàn)###
需求####
這里我們的需求很簡(jiǎn)單:
點(diǎn)擊按鈕,執(zhí)行一個(gè)網(wǎng)絡(luò)請(qǐng)求点弯,將返回的json信息解析扇调,實(shí)現(xiàn)UI 更新
這也是我們做APP最常用的套路。首先看一下抢肛,我們需要 實(shí)現(xiàn)的效果狼钮。
看到網(wǎng)上關(guān)于RxJava的網(wǎng)絡(luò)請(qǐng)求的內(nèi)容,都會(huì)提及Retrofit的使用捡絮,然而由于Retrofit使用了注解相關(guān)的內(nèi)容熬芜,代碼看起來(lái)會(huì)有點(diǎn)不好理解,這里我們就從最基礎(chǔ)的網(wǎng)絡(luò)請(qǐng)求出發(fā)福稳,一步一步理解一下RxAndroid的使用涎拉。
RxAndroid+OkHttp+Gson 實(shí)現(xiàn)數(shù)據(jù)更新####
OkHttp
OKHttp 大家應(yīng)該都了解,OkHttp 是基于http協(xié)議封裝的一套請(qǐng)求客戶端的圆。具體的細(xì)節(jié)就不展開說(shuō)了鼓拧,這里直接使用。
- 我們創(chuàng)建OKHttpClient 和 Request
client = new OkHttpClient();
request = new Request.Builder()
.url(BaseUrl)
.build();
- 創(chuàng)建Observeable (OKHttp 同步執(zhí)行)
private Observable<Response> HttpService() {
Observable myObserve;
myObserve = Observable.create(new Observable.OnSubscribe<Response>() {
@Override
public void call(Subscriber<? super Response> subscriber) {
Response response = null;
try {
response = client.newCall(request).execute();
subscriber.onNext(response);
subscriber.onCompleted();
} catch (IOException e) {
subscriber.onError(e);
}
}
});
這里我們通過(guò)oncreate 操作符創(chuàng)建了一個(gè)Observeable越妈,在其call 方法中執(zhí)行了OkHttp的一個(gè)同步get請(qǐng)求季俩,
網(wǎng)絡(luò)請(qǐng)求正常時(shí),將請(qǐng)求響應(yīng)Resoponse通過(guò)onNext方法返回梅掠,同時(shí)執(zhí)行onCompleted方法酌住。
網(wǎng)絡(luò)請(qǐng)求異常時(shí),將異常信息通過(guò)onError方法返回阎抒。
- 訂閱者執(zhí)行subscribe
private void getData() {
HttpService()
.subscribe(new Subscriber<Response>() {
@Override
public void onCompleted() {
Log.e("onCompleted", "onCompleted");
}
@Override
public void onError(Throwable e) {
Log.e("onError", e.getMessage());
}
@Override
public void onNext(Response response) {
if (response.isSuccessful()) {
try {
String json = response.body().string();
Log.e("onNext", json);
setView(json);
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
}
通過(guò)之前的學(xué)習(xí)酪我,我們知道在訂閱者(Subscribe)實(shí)現(xiàn)訂閱(subscribe)操作的同時(shí),Observeable就會(huì)開始發(fā)送事件挠蛉,在我們當(dāng)前的例子里祭示,就是開始執(zhí)行oncall方法肄满,通過(guò)OKHttp的網(wǎng)絡(luò)請(qǐng)求谴古,將請(qǐng)求到的信息Response通過(guò)onNext返回,而在訂閱者的onNext 方法里稠歉,我們處理Response信息掰担,實(shí)現(xiàn)UI更新也糊。
- 指定正確的執(zhí)行線程
你應(yīng)該已經(jīng)注意到仅政,上面一個(gè)簡(jiǎn)單的流程里辩昆,我們進(jìn)行了網(wǎng)絡(luò)請(qǐng)求煎饼、UI更新等操作舀奶,而這些操作必然是在不同的線程中完成,這就要求我們整個(gè)操作流程必須實(shí)現(xiàn)正確的線程切換碌宴,RxJava 固然強(qiáng)大页慷,但也無(wú)法實(shí)現(xiàn)線程的智能切換 ,必須由我們?nèi)ブ付ê线m的線程执庐。所以我們上面的代碼是有問(wèn)題的酪耕,需要進(jìn)行如下修改:
private void getData() {
HttpService()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Response>() {
onCompleted();
......unchange
}
這里我們的修改很簡(jiǎn)單,兩行關(guān)鍵代碼:
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
這兩行代碼指定了轨淌,我們的網(wǎng)絡(luò)請(qǐng)求在io線程執(zhí)行迂烁,不會(huì)阻塞主線程;UI更新確保在主線程中執(zhí)行递鹉。
總結(jié)來(lái)說(shuō)盟步,這里我們使用到了RxJava中的調(diào)度器,就是subscribeOn 指定了Observeable 執(zhí)行的線程躏结;而observeOn指定了Subscribe(訂閱者)執(zhí)行的線程却盘。
這樣我們非常簡(jiǎn)單實(shí)現(xiàn)了對(duì)線程的控制。
- 以正確的方式更新UI
好了窜觉,我們現(xiàn)在可以放心的執(zhí)行g(shù)etData方法了 谷炸,在其onNext 方法,我們接收Response中的數(shù)據(jù):
這里分享一下禀挫,我在使用這個(gè)OKHttp 的Response時(shí)遇到一個(gè)坑:
Log.e("onNext", response.body().string());
String json = response.body().string();
Log.e("onNext", json);
執(zhí)行上面的三行代碼旬陡,你會(huì)發(fā)現(xiàn),第一次打印的日志是有數(shù)據(jù)的语婴,而第二次打印的日志數(shù)據(jù)卻是null描孟,第一次看到這個(gè)情況的時(shí)候,真的是讓我驚呆了砰左,后來(lái)看了body 方法的API才明白:
/**
* Never {@code null}, must be closed after consumption, can be consumed only once.
*/
public ResponseBody body() {
return body;
}
原來(lái)這個(gè)boby方法只能被執(zhí)行一次匿醒。這個(gè)真是有點(diǎn)坑啊2肌A帷!僻造!每次獲取數(shù)據(jù)都有打印日志的習(xí)慣憋他,真不知道只能執(zhí)行一次的意義是什么。
好了髓削,我們繼續(xù)竹挡,數(shù)據(jù)已經(jīng)能正確接收了,接下來(lái)就是解析數(shù)據(jù)并更新UI 了立膛。
public void setView(String json) {
Gson gson = new Gson();
DoubanBean douban = new DoubanBean();
douban = gson.fromJson(json, DoubanBean.class);
//
Glide.with(mContext).load(douban.getIcon()).into(pic);
title.setText(douban.getTitle());
id.setText(douban.getId());
}
這里我們用Gson 解析返回的json 格式數(shù)據(jù)揪罕,實(shí)現(xiàn)View 內(nèi)容更新梯码。
這里我們調(diào)用getData方法,結(jié)果發(fā)現(xiàn)頁(yè)面沒(méi)有任何變化好啰,看Logcat日志輸出:
E/onError: Permission denied (missing INTERNET permission?)
原來(lái)是我們忘記在AndroidManifest 文件中聲明網(wǎng)絡(luò)請(qǐng)求的權(quán)限了轩娶,這里執(zhí)行了onError 方法,返回了異常信息框往。
我們加上INTERNET 相關(guān)的權(quán)限之后罢坝,運(yùn)行程序,發(fā)現(xiàn)可以正常執(zhí)行了搅窿。
這里可以看到嘁酿,RxJava的響應(yīng)式編程思想中,對(duì)錯(cuò)誤的處理也是很理性的男应。
- 創(chuàng)建Observeable (OKHttp 異步執(zhí)行)
之前我們創(chuàng)建Observeable的方式是通過(guò)OKHttp的同步get請(qǐng)求方式闹司,如果用異步請(qǐng)求方式怎么做呢?
// OkHttp 異步執(zhí)行
myObserve=Observable.create(new Observable.OnSubscribe<Response>() {
@Override
public void call(final Subscriber<? super Response> subscriber) {
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
subscriber.onError(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
subscriber.onNext(response);
subscriber.onCompleted();
}
});
}
});
看以看到沐飘,和同步請(qǐng)求方式不同的是游桩,我們將onNext ,onCompleted 和 onError這些回調(diào)方法放在了OKHttp自己的回調(diào)里進(jìn)行執(zhí)行。這樣做的唯一優(yōu)點(diǎn)可能就是我們?cè)趫?zhí)行訂閱的時(shí)候不用指定Observeable(網(wǎng)絡(luò)請(qǐng)求)執(zhí)行的線程了耐朴,因?yàn)樗旧砭褪钱惒降慕栉裕褪沁@里:
private void getData() {
HttpService()
//okHttp 異步執(zhí)行時(shí),無(wú)需指定網(wǎng)絡(luò)請(qǐng)求的線程
// .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.......
}
當(dāng)然筛峭,OkHttp終究只是對(duì)網(wǎng)絡(luò)請(qǐng)求做了一次封裝的庫(kù)铐刘,和最基礎(chǔ)的HttpClient, HttpUrlConnection的功能是一樣的,不像Volley影晓、android-async-http這些庫(kù)镰吵;無(wú)論同步執(zhí)行還是異步執(zhí)行,其請(qǐng)求結(jié)果始終是在子線程挂签,所以我們的Subscribe對(duì)于UI的更新還是需要指定其為mainThread 的疤祭。
這里可以看出,使用異步的OKHttp反而有點(diǎn)多余了饵婆。
后話###
這里我們通過(guò) RxAndroid+OkHttp+Gson 的方式勺馆,以一種最費(fèi)勁的方式實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的需求(這個(gè)Demo真的很爛),只是為了闡述RxJava 的編程思想在Android中使用的體驗(yàn)侨核。這里的需求草穆,通過(guò)AsnycTask 或者OkHttp + Handler 的方式實(shí)現(xiàn)是非常簡(jiǎn)單的,就不再詳述了芹关。
RxJava 的作用就是實(shí)現(xiàn)異步续挟,如果我們?cè)镜牟僮鞅緛?lái)就是異步紧卒,為了使用RxJava而硬套進(jìn)去是不合理的侥衬,反而顯得有點(diǎn)不倫不類,這里我們從Observeable的創(chuàng)建使用OkHttp 的同步&異步請(qǐng)求就可以看出,使用異步請(qǐng)求并沒(méi)有多大益處轴总,反而丟掉了RxJava可以指定線程的優(yōu)點(diǎn)直颅。
RxJava的使用并不能使我們的程序運(yùn)行更高效,或者可以實(shí)現(xiàn)了別的框架實(shí)現(xiàn)不了的功能怀樟。只是對(duì)我們編寫代碼的方式提供了一種更好的思路功偿。
好了,RxJava 基礎(chǔ)到這里就結(jié)束了往堡。文中所講的Demo在GitHub中也有械荷,感興趣的同學(xué)可以點(diǎn)這里。