在Retrofit中加入RxJava

這篇文章的由來

目前項(xiàng)目中引入了RxJava,而我在其他項(xiàng)目里分別使用過Retrofit以及Retrofit+ RxJava。以自己的感受而言,RxJava確實(shí)很強(qiáng)大,而且對(duì)于編碼效率和代碼簡潔性有不小的提升,所以簡單對(duì)比一下兩者的區(qū)別。本文默認(rèn)讀者已熟悉RxJava的基本Api以及使用場景,若非如此,則參考該文章:http://gank.io/post/560e15be2dca930e00da1083。

干貨

基本使用

在目前的項(xiàng)目里,使用RetrofitRetrofit + RxJava的場景幾乎類似,代碼上有一點(diǎn)區(qū)別:

  1. StickerServerApi中寫下接口方法:
// 使用Retrofit
@GET("path")
Call<T> apiName(@QueryMap Map<String, String> params);
// 使用Retrofit + RxJava
@GET("path")
Observable<T> apiName(@QueryMap Map<String, String> params);
  1. WebService中,調(diào)用StickerServerApi中的方法:
// 使用Retrofit
@MainThread
public void requestApi(Callback<T> callback) {
    Map<String, String> params = getParamsPacker().pack();
    Call<T> call = mStickerServerApi.apiName(params);
    call.enqueue(callback);
}
// 使用Retrofit + RxJava
public Observable<T> requestApi() {
    Map<String, String> params = getParamsPacker().pack();
    return mStickerServerApi.apiName(params);
}
  1. Repository中,調(diào)用WebService中的方法,并處理響應(yīng)邏輯:
// 使用Retrofit
public LiveData<Resource<T>> requestApi() {
    getWebService().requestApi(new Callback<T>() {
        @Override
        public void onResponse(Call<T> call, Response<T> response) {
            mLiveData.setValue(Resource.success(response.body());
        }

        @Override
        public void onFailure(Call<T> call, Throwable t) {
            mLiveData.setValue(Resource.error(t.message);
        }
    });
    mLiveData.setValue(Resource.loading(null));
    return mLiveData;
}
// 使用Retrofit + RxJava
public LiveData<Resource<T>> requestApi() {
    getWebService().requestApi()
                // 在子線程調(diào)用接口
                .subscribeOn(Schedulers.io())
                // 在主線程調(diào)用回調(diào)方法
                .observeOn(AndroidSchedulers.mainThread())
                // subscribe方法針對(duì)不同的參數(shù)有很多的重載方法
                // 下文傳入Observer對(duì)象的重載方法是相對(duì)回調(diào)最多的,所以看起來似乎比上面的代碼更復(fù)雜
                // 實(shí)際使用中可以使用其他重載方法以傳入更為簡單的接口對(duì)象
                .subscribe(new Observer<BaseData<List<StarResponseModel>>>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        // 在訂閱時(shí)觸發(fā),這里可以不作處理
                    }

                    @Override
                    public void onNext(T t) {
                        // 相當(dāng)于onResponse,和onError互斥觸發(fā)
                        mLiveData.setValue(Resource.success(t);
                    }

                    @Override
                    public void onError(Throwable e) {
                        // onFail,和onNext互斥觸發(fā)
                        mLiveData.setValue(Resource.error(t.message);
                    }

                    @Override
                    public void onComplete() {
                        // 在onNext或者onError后觸發(fā),可以不作處理
                    }
                })
    mLiveData.setValue(Resource.loading(null));
    return mLiveData;
}
  1. View層進(jìn)行liveData的訂閱,處理相應(yīng)的UI變化。這部分的代碼沒有區(qū)別,不再贅述。

復(fù)雜情景中的使用

這部分與基本使用中的代碼區(qū)別在于Repository中的邏輯,所以只貼出Repository中的代碼。

  1. 接口的循環(huán)調(diào)用。某些場景下,需要先請(qǐng)求接口1獲取響應(yīng)數(shù)據(jù),并作為接口2的請(qǐng)求參數(shù),而最終的邏輯需要在接口2的響應(yīng)方法中執(zhí)行。在項(xiàng)目中也有這樣的情景,比如上傳資源文件到阿里云后臺(tái),然后將地址發(fā)送給服務(wù)器。
// 使用Retrofit
public LiveData<Resource<T>> requestApi() {
    getWebService().requestApi1(new Callback<T>() {
        @Override
        public void onResponse(Call<T> call, Response<T> response) {
            // api1的返回值是api2的請(qǐng)求參數(shù)
            T t = response.body();
            getWebService().requestApi2(t, new Callback<K>() {
                @Override
                public void onResponse(Call<K> call, Response<K> response) {
                    mLiveData.setValue(Resource.success(response.body());
                }

                @Override
                public void onFailure(Call<K> call, Throwable t) {
                    mLiveData.setValue(Resource.error(t.message);
                }
            });
        }

        @Override
        public void onFailure(Call<T> call, Throwable t) {
            mLiveData.setValue(Resource.error(t.message);
        }
    });
    mLiveData.setValue(Resource.loading(null));
    return mLiveData;
}
// 使用Retrofit + RxJava
public LiveData<Resource<T>> requestApi() {
    getWebService().requestApi1()
                // 在子線程調(diào)用接口
                .subscribeOn(Schedulers.io())
                .flatMap(new Function<T, ObservableSource<K>>() {
                    @Override
                    public ObservableSource<K> apply(T t) throws Exception {
                        // api1的返回值是api2的請(qǐng)求參數(shù)
                        return getWebService().requestApi2(t);
                    }
                })
                // 在主線程調(diào)用回調(diào)方法
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<K>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        // 在訂閱時(shí)觸發(fā),這里可以不作處理
                    }

                    @Override
                    public void onNext(K k) {
                        // 相當(dāng)于onResponse,和onError互斥觸發(fā)
                        mLiveData.setValue(Resource.success(k);
                    }

                    @Override
                    public void onError(Throwable t) {
                        // onFail,和onNext互斥觸發(fā)
                        mLiveData.setValue(Resource.error(t.message);
                    }

                    @Override
                    public void onComplete() {
                        // 在onNext或者onError后觸發(fā),可以不作處理
                    }
                })
    mLiveData.setValue(Resource.loading(null));
    return mLiveData;
}

可以看到,在Retrofit中,想要實(shí)現(xiàn)接口套接口的邏輯,需要兩層Callback嵌套,而如果加入了RxJava,則只需要調(diào)用flatMap()就可以了。前者的多層嵌套相比后者無論從開發(fā)效率還是代碼可讀性而言都要略遜一籌。而這只是兩層嵌套,如果是多層嵌套,差距更顯而易見。

  1. 在接收到響應(yīng)數(shù)據(jù)后,進(jìn)行一些異步操作。
    網(wǎng)絡(luò)請(qǐng)求的回調(diào)方法通常需要進(jìn)行UI更新,所以一般回調(diào)方法都是在主線程中運(yùn)行。而如果這時(shí)需要進(jìn)行一些異步操作,比如io讀取、數(shù)據(jù)庫存取,代碼就會(huì)比較復(fù)雜。以下以下載視頻為例。
// 使用Retrofit
public LiveData<Resource<File>> requestApi() {
    getWebService().requestApi(new Callback<Video>() {
        @Override
        public void onResponse(Call<Video> call, Response<Video> response) {
            Video video = response.body();
            final String url = video.url;
            final Handler handler = new Handler();
            new Thread() {
                @Override
                public void run() {
                    File file = new File("filePath");
                    // 寫文件邏輯省略
                    ...  
                    // 切回 UI 線程
                    handler.post(new Runnable() { 
                        @Override
                        public void run() {
                            // 可能存在的其他邏輯省略
                            ...
                            // liveData賦值
                            mLiveData.setValue(Resource.success(file))
                        }
                    });
                }
            }).start();
        }

        @Override
        public void onFailure(Call<T> call, Throwable t) {
            mLiveData.setValue(Resource.error(t.message);
        }
    });
    mLiveData.setValue(Resource.loading(null));
    return mLiveData;
}
// 使用Retrofit + RxJava
public LiveData<Resource<File>> requestApi() {
    getWebService().requestApi()
                // 在子線程調(diào)用接口
                .subscribeOn(Schedulers.io())
                .map(new Function<T>, File>() {
                    @Override
                    public File apply(T t) throws Exception {
                        File file = new File("filePath");
                        // 省略寫文件邏輯
                        ...
                        // 返回文件
                        return file;
                    }
                })
                // 切換回主線程
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<File>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        // 在訂閱時(shí)觸發(fā),這里可以不作處理
                    }

                    @Override
                    public void onNext(File file) {
                        // 相當(dāng)于onResponse,和onError互斥觸發(fā)
                        // 其他邏輯
                        ...
                        // liveData賦值
                        mLiveData.setValue(Resource.success(file);
                    }

                    @Override
                    public void onError(Throwable t) {
                        // onFail,和onNext互斥觸發(fā)
                        mLiveData.setValue(Resource.error(t.message);
                    }

                    @Override
                    public void onComplete() {
                        // 在onNext或者onError后觸發(fā),可以不作處理
                    }
                })
    mLiveData.setValue(Resource.loading(null));
    return mLiveData;
}

對(duì)比這一場景中的兩部分代碼,同樣地,單獨(dú)使用Retrofit時(shí),動(dòng)輒兩三層的縮進(jìn),以及onResponse()方法中大量的代碼,都會(huì)降低可讀性和開發(fā)效率。在加入了RxJava后,只需要一個(gè)map()方法(還有其他有用的api,這里暫時(shí)不提),再加上RxJava的線程調(diào)度特性,就使代碼看起來簡單了許多。

總結(jié)

現(xiàn)在很多文章都推薦使用RxJavaRetrofit進(jìn)行網(wǎng)絡(luò)請(qǐng)求框架的搭建,而且Retrofit本身也對(duì)RxJava進(jìn)行了支持,這就足夠說明加入RxJava是有一定的意義的。而我自己的使用經(jīng)驗(yàn)也使得我更偏向于結(jié)合RxJava來使用Retrofit。但這畢竟只是個(gè)工具,而且相對(duì)陌生,有一定的學(xué)習(xí)成本,并且開發(fā)效率受到熟練度的影響。但不論最終是否加入RxJava,多了解一下也是有好處的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 原文地址:http://gank.io/post/560e15be2dca930e00da1083 前言 我從去年...
    AFinalStone閱讀 2,328評(píng)論 5 23
  • 轉(zhuǎn)一篇文章 原地址:http://gank.io/post/560e15be2dca930e00da1083 前言...
    jack_hong閱讀 1,030評(píng)論 0 2
  • 好久沒來這里了,再來……已恍如隔世! 2019年2月18日,今天,是我人生最重要的分水嶺! 過去的,不愿再去回頭,...
    AmyMoonlight閱讀 670評(píng)論 0 0
  • 神秘的尾周末,無比神秘,精神上的洗禮,更愛大家和死黨
    陳琦不黑閱讀 138評(píng)論 0 2
  • “小可,你長大以后想做什么呀?” “科學(xué)家!” 六歲時(shí),面對(duì)七大姑八大姨挑逗式的提問,林可總會(huì)驕傲地仰起臉,不假思...
    安五香閱讀 212評(píng)論 0 1

友情鏈接更多精彩內(nèi)容