Retrofit与RXJava整合
Retrofit 除了提供了傳統(tǒng)的 Callback 形式的 API,還有 RxJava 版本的 Observable 形式 API。下面我用對(duì)比的方式來介紹 Retrofit 的 RxJava 版 API 和傳統(tǒng)版本的區(qū)別。
以獲取一個(gè) User 對(duì)象的接口作為例子。使用Retrofit 的傳統(tǒng) API,你可以用這樣的方式來定義請(qǐng)求:
@GET("/user") public void getUser(@Query("userId") String userId, Callback<User> callback);在程序的構(gòu)建過程中, Retrofit 會(huì)把自動(dòng)把方法實(shí)現(xiàn)并生成代碼,然后開發(fā)者就可以利用下面的方法來獲取特定用戶并處理響應(yīng):
getUser(userId, new Callback<User>() {@Overridepublic void success(User user) {userView.setUser(user);}@Overridepublic void failure(RetrofitError error) {// Error handling...} };而使用 RxJava 形式的 API,定義同樣的請(qǐng)求是這樣的:
@GET("/user") public Observable<User> getUser(@Query("userId") String userId);使用的時(shí)候是這樣的:
getUser(userId).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<User>() {@Overridepublic void onNext(User user) {userView.setUser(user);}@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable error) {// Error handling...}});看到區(qū)別了嗎?
當(dāng) RxJava 形式的時(shí)候,Retrofit 把請(qǐng)求封裝進(jìn) Observable ,在請(qǐng)求結(jié)束后調(diào)用 onNext() 或在請(qǐng)求失敗后調(diào)用 onError()。
對(duì)比來看, Callback 形式和 Observable 形式長(zhǎng)得不太一樣,但本質(zhì)都差不多,而且在細(xì)節(jié)上 Observable 形式似乎還比 Callback 形式要差點(diǎn)。那 Retrofit 為什么還要提供 RxJava 的支持呢?
因?yàn)樗糜冒?#xff01;從這個(gè)例子看不出來是因?yàn)檫@只是最簡(jiǎn)單的情況。而一旦情景復(fù)雜起來, Callback 形式馬上就會(huì)開始讓人頭疼。比如:
假設(shè)這么一種情況:你的程序取到的 User 并不應(yīng)該直接顯示,而是需要先與數(shù)據(jù)庫(kù)中的數(shù)據(jù)進(jìn)行比對(duì)和修正后再顯示。使用 Callback 方式大概可以這么寫:
getUser(userId, new Callback<User>() {@Overridepublic void success(User user) {processUser(user); // 嘗試修正 User 數(shù)據(jù)userView.setUser(user);}@Overridepublic void failure(RetrofitError error) {// Error handling...} };有問題嗎?
很簡(jiǎn)便,但不要這樣做。為什么?因?yàn)檫@樣做會(huì)影響性能。數(shù)據(jù)庫(kù)的操作很重,一次讀寫操作花費(fèi) 10~20ms 是很常見的,這樣的耗時(shí)很容易造成界面的卡頓。所以通常情況下,如果可以的話一定要避免在主線程中處理數(shù)據(jù)庫(kù)。所以為了提升性能,這段代碼可以優(yōu)化一下:
getUser(userId, new Callback<User>() {@Overridepublic void success(User user) {new Thread() {@Overridepublic void run() {processUser(user); // 嘗試修正 User 數(shù)據(jù)runOnUiThread(new Runnable() { // 切回 UI 線程@Overridepublic void run() {userView.setUser(user);}});}).start();}@Overridepublic void failure(RetrofitError error) {// Error handling...} };性能問題解決,但……這代碼實(shí)在是太亂了,迷之縮進(jìn)啊!雜亂的代碼往往不僅僅是美觀問題,因?yàn)榇a越亂往往就越難讀懂,而如果項(xiàng)目中充斥著雜亂的代碼,無疑會(huì)降低代碼的可讀性,造成團(tuán)隊(duì)開發(fā)效率的降低和出錯(cuò)率的升高。
這時(shí)候,如果用 RxJava 的形式,就好辦多了。 RxJava 形式的代碼是這樣的:
getUser(userId).doOnNext(new Action1<User>() {@Overridepublic void call(User user) {processUser(user);}).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<User>() {@Overridepublic void onNext(User user) {userView.setUser(user);}@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable error) {// Error handling...}});其中
doOnNext()的執(zhí)行在onNext()之前,對(duì)數(shù)據(jù)進(jìn)行相關(guān)處理。doOnNext在哪一個(gè)線程處理,暫時(shí)不明。
參考鏈接
RxJava操作符doOnNext - 享受技術(shù)帶來的快樂! - 博客頻道 - CSDN.NET
Rxjava中的doOnNext的作用和在哪里執(zhí)行 - u010746364的博客 - 博客頻道 - CSDN.NET
后臺(tái)代碼和前臺(tái)代碼全都寫在一條鏈中,明顯清晰了很多。
再舉一個(gè)例子:假設(shè) /user 接口并不能直接訪問,而需要填入一個(gè)在線獲取的 token ,代碼應(yīng)該怎么寫?
Callback 方式,可以使用嵌套的 Callback:
@GET("/token") public void getToken(Callback<String> callback);@GET("/user") public void getUser(@Query("token") String token, @Query("userId") String userId, Callback<User> callback);...getToken(new Callback<String>() {@Overridepublic void success(String token) {getUser(token, userId, new Callback<User>() {@Overridepublic void success(User user) {userView.setUser(user);}@Overridepublic void failure(RetrofitError error) {// Error handling...}};}@Overridepublic void failure(RetrofitError error) {// Error handling...} });倒是沒有什么性能問題,可是迷之縮進(jìn)毀一生,你懂我也懂,做過大項(xiàng)目的人應(yīng)該更懂。
而使用 RxJava 的話,代碼是這樣的:
@GET("/token") public Observable<String> getToken();@GET("/user") public Observable<User> getUser(@Query("token") String token, @Query("userId") String userId);...getToken().flatMap(new Func1<String, Observable<User>>() {@Overridepublic Observable<User> onNext(String token) {return getUser(token, userId);}).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<User>() {@Overridepublic void onNext(User user) {userView.setUser(user);}@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable error) {// Error handling...}});用一個(gè) flatMap() 就搞定了邏輯,依然是一條鏈。看著就很爽,是吧?
RxJava配合Retrofit2.0使用
新的Retrofit2.0簡(jiǎn)直就是設(shè)計(jì)模式的教科書典范,同時(shí)對(duì)Rx的支持也更加友好,本例子為查詢ip獲取地理信息,并過濾掉失敗信息
//使用Rxjava配合Retrofit解析json數(shù)據(jù),注意這里全是電腦運(yùn)行的,沒有分開線程訂閱 public static void main(String[] args) throws Exception{ OkHttpClient client = new OkHttpClient(); client.interceptors().add(new LoggingInterceptor());//log for okhttpRetrofit retrofit = new Retrofit.Builder().baseUrl(IPService.END).client(client).addConverterFactory(GsonConverterFactory.create())//對(duì)Response進(jìn)行adapter轉(zhuǎn)換.addCallAdapterFactory(RxJavaCallAdapterFactory.create())//對(duì)轉(zhuǎn)換后的數(shù)據(jù)進(jìn)行再包裝.build();retrofit.create(IPService.class)//動(dòng)態(tài)代理生成class//直接操作json數(shù)據(jù),這里可不是一個(gè)好的習(xí)慣,真正應(yīng)該是DTO對(duì)象的.getIPInfo("58.19.239.11").filter(jsonObject -> jsonObject.get("code").getAsInt()==0)//轉(zhuǎn)換數(shù)據(jù)類型.map(jsonObject1 -> jsonObject1.get("data"))//輸出結(jié)果.subscribe(System.out::println); }//retrofit定義的接口 interface IPService {String END = "http://ip.taobao.com";//建議寫成dto對(duì)象,博主只是為了演示filter就把這里JsonObject了@GET("/service/getIpInfo.php") Observable<JsonObject> getIPInfo(@Query("ip") String ip); }/** * Retrofit2.0已經(jīng)把網(wǎng)絡(luò)部分剝離了,所以需要自己實(shí)現(xiàn)Log */ static class LoggingInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException {Request request = chain.request();long t1 = System.nanoTime();System.out.println(String.format("Sending request %s on %s%n%s", request.url(), chain.connection(),request.headers()));Response response = chain.proceed(request);long t2 = System.nanoTime();System.out.println(String.format("Received response for %s in %.1fms%n%s", response.request().url(),(t2 - t1) / 1e6d, response.headers()));return response; }源代碼
rengwuxian RxJava Samples
參考鏈接
給 Android 開發(fā)者的 RxJava 詳解
函數(shù)式編程RxJava操作實(shí)例 - 簡(jiǎn)書
總結(jié)
以上是生活随笔為你收集整理的Retrofit与RXJava整合的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python实现简单爬虫抓取图片
- 下一篇: 指针%p输出的一些认识