什么是RxJava##
- RxJava 就是異步
- RxJava 的異步實現,是通過一種擴展的觀察者模式來實現的。
- 一個響應式編程框架
通過之前對RxJava的了解,我們已經掌握了RxJava的一些基礎使用方法,下面我們結合一個簡單的Demo,看看如何在Android 開發中使用RxJava。
RxAndroid 初體驗###
需求####
這里我們的需求很簡單:
點擊按鈕,執行一個網絡請求,將返回的json信息解析,實現UI 更新
這也是我們做APP最常用的套路。首先看一下,我們需要 實現的效果。
看到網上關于RxJava的網絡請求的內容,都會提及Retrofit的使用,然而由于Retrofit使用了注解相關的內容,代碼看起來會有點不好理解,這里我們就從最基礎的網絡請求出發,一步一步理解一下RxAndroid的使用。
RxAndroid+OkHttp+Gson 實現數據更新####
OkHttp
OKHttp 大家應該都了解,OkHttp 是基于http協議封裝的一套請求客戶端。具體的細節就不展開說了,這里直接使用。
- 我們創建OKHttpClient 和 Request
client = new OkHttpClient();
request = new Request.Builder()
.url(BaseUrl)
.build();
- 創建Observeable (OKHttp 同步執行)
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);
}
}
});
這里我們通過oncreate 操作符創建了一個Observeable,在其call 方法中執行了OkHttp的一個同步get請求,
網絡請求正常時,將請求響應Resoponse通過onNext方法返回,同時執行onCompleted方法。
網絡請求異常時,將異常信息通過onError方法返回。
- 訂閱者執行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();
}
}
}
});
}
通過之前的學習,我們知道在訂閱者(Subscribe)實現訂閱(subscribe)操作的同時,Observeable就會開始發送事件,在我們當前的例子里,就是開始執行oncall方法,通過OKHttp的網絡請求,將請求到的信息Response通過onNext返回,而在訂閱者的onNext 方法里,我們處理Response信息,實現UI更新。
- 指定正確的執行線程
你應該已經注意到,上面一個簡單的流程里,我們進行了網絡請求、UI更新等操作,而這些操作必然是在不同的線程中完成,這就要求我們整個操作流程必須實現正確的線程切換,RxJava 固然強大,但也無法實現線程的智能切換 ,必須由我們去指定合適的線程。所以我們上面的代碼是有問題的,需要進行如下修改:
private void getData() {
HttpService()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Response>() {
onCompleted();
......unchange
}
這里我們的修改很簡單,兩行關鍵代碼:
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
這兩行代碼指定了,我們的網絡請求在io線程執行,不會阻塞主線程;UI更新確保在主線程中執行。
總結來說,這里我們使用到了RxJava中的調度器,就是subscribeOn 指定了Observeable 執行的線程;而observeOn指定了Subscribe(訂閱者)執行的線程。
這樣我們非常簡單實現了對線程的控制。
- 以正確的方式更新UI
好了,我們現在可以放心的執行getData方法了 ,在其onNext 方法,我們接收Response中的數據:
這里分享一下,我在使用這個OKHttp 的Response時遇到一個坑:
Log.e("onNext", response.body().string());
String json = response.body().string();
Log.e("onNext", json);
執行上面的三行代碼,你會發現,第一次打印的日志是有數據的,而第二次打印的日志數據卻是null,第一次看到這個情況的時候,真的是讓我驚呆了,后來看了body 方法的API才明白:
/**
* Never {@code null}, must be closed after consumption, can be consumed only once.
*/
public ResponseBody body() {
return body;
}
原來這個boby方法只能被執行一次。這個真是有點坑啊!!?。∶看潍@取數據都有打印日志的習慣,真不知道只能執行一次的意義是什么。
好了,我們繼續,數據已經能正確接收了,接下來就是解析數據并更新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 格式數據,實現View 內容更新。
這里我們調用getData方法,結果發現頁面沒有任何變化,看Logcat日志輸出:
E/onError: Permission denied (missing INTERNET permission?)
原來是我們忘記在AndroidManifest 文件中聲明網絡請求的權限了,這里執行了onError 方法,返回了異常信息。
我們加上INTERNET 相關的權限之后,運行程序,發現可以正常執行了。
這里可以看到,RxJava的響應式編程思想中,對錯誤的處理也是很理性的。
- 創建Observeable (OKHttp 異步執行)
之前我們創建Observeable的方式是通過OKHttp的同步get請求方式,如果用異步請求方式怎么做呢?
// OkHttp 異步執行
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();
}
});
}
});
看以看到,和同步請求方式不同的是,我們將onNext ,onCompleted 和 onError這些回調方法放在了OKHttp自己的回調里進行執行。這樣做的唯一優點可能就是我們在執行訂閱的時候不用指定Observeable(網絡請求)執行的線程了,因為他本身就是異步的,就是這里:
private void getData() {
HttpService()
//okHttp 異步執行時,無需指定網絡請求的線程
// .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.......
}
當然,OkHttp終究只是對網絡請求做了一次封裝的庫,和最基礎的HttpClient, HttpUrlConnection的功能是一樣的,不像Volley、android-async-http這些庫;無論同步執行還是異步執行,其請求結果始終是在子線程,所以我們的Subscribe對于UI的更新還是需要指定其為mainThread 的。
這里可以看出,使用異步的OKHttp反而有點多余了。
后話###
這里我們通過 RxAndroid+OkHttp+Gson 的方式,以一種最費勁的方式實現了一個簡單的需求(這個Demo真的很爛),只是為了闡述RxJava 的編程思想在Android中使用的體驗。這里的需求,通過AsnycTask 或者OkHttp + Handler 的方式實現是非常簡單的,就不再詳述了。
RxJava 的作用就是實現異步,如果我們原本的操作本來就是異步,為了使用RxJava而硬套進去是不合理的,反而顯得有點不倫不類,這里我們從Observeable的創建使用OkHttp 的同步&異步請求就可以看出,使用異步請求并沒有多大益處,反而丟掉了RxJava可以指定線程的優點。
RxJava的使用并不能使我們的程序運行更高效,或者可以實現了別的框架實現不了的功能。只是對我們編寫代碼的方式提供了一種更好的思路。
好了,RxJava 基礎到這里就結束了。文中所講的Demo在GitHub中也有,感興趣的同學可以點這里。