天天看點

安卓項目實戰之強大的網絡請求架構okGo使用詳解(五):擴充項目okRx,完美結合RxJava

前言

在第一篇講解okGo架構添加依賴支援時,還記得我們額外添加的兩個依賴嗎,一個okRx和一個okServer,這兩個均是基于okGo架構的擴充項目,其中okRx可以使請求結合RxJava一起使用,而okServer則提供了強大的下載下傳上傳功能,如斷點支援,多任務管理等,本篇我們主要講解okRx的使用。

OkRx主要功能

1,可以很完美結合RxJava做網絡請求

2,在使用上比Retrofit更簡單友善,門檻更低,靈活性更高

3,網絡請求和RxJava調用可以做成一條鍊試,寫法優雅

4,使用Converter接口,支援任意類型的資料自動解析

5,OkRx是擴充的OkGo,是以OkGo包含的所有功能和寫法,OkRx全部支援

Rx請求的寫法

1,擷取Observable對象

我們還是像正常使用OkGo的方式一樣,傳入我們需要請求的url,和我們需要的參數,寫法如下:

安卓項目實戰之強大的網絡請求架構okGo使用詳解(五):擴充項目okRx,完美結合RxJava

這裡有兩個特殊的方法:

.converter():該方法參數是網絡請求的轉換器類執行個體,功能是将網絡請求的結果轉換成我們需要的資料類型。
 .adapt():該方法是方法傳回值的擴充卡,功能是将網絡請求的Call<T>對象,适配成我們需要的Observable<T>對象。
           

2. 調用Rx轉換代碼

安卓項目實戰之強大的網絡請求架構okGo使用詳解(五):擴充項目okRx,完美結合RxJava

上面兩步放在一起寫,如下:

安卓項目實戰之強大的網絡請求架構okGo使用詳解(五):擴充項目okRx,完美結合RxJava

上面的showLoading和dismissLoading方法是我們在BaseActivity中定義的顯示進度和隐藏進度的方法。

private ProgressDialog dialog;

    public void showLoading() {
        if (dialog != null && dialog.isShowing()) return;
        dialog = new ProgressDialog(this);
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        dialog.setCanceledOnTouchOutside(false);
        dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        dialog.setMessage("請求網絡中...");
        dialog.show();
    }

    public void dismissLoading() {
        if (dialog != null && dialog.isShowing()) {
            dialog.dismiss();
        }
    }
           

addDisposable方法是取消請求時使用,見下面取消請求部分講解。

以上大概就是使用okGo結合RxJava使用的完整案例,其中有兩個地方作如下主要說明:

Converter詳解

convert接口實作類的作用是用來進行資料轉換的,即将網絡請求擷取到的資料轉換成我們泛型指定的對象,作用和retrofit中的gson轉換一樣,基于此種寫法我們就必須額外定義一個繼承Convert接口重寫convertResponse方法編寫解析轉換邏輯的實作類,因為.converter()參數為該轉換器類的一個執行個體,就不能像之前隻使用okGo那樣可以将該部分邏輯直接寫進callback實作類中的convertResponse方法之中而不去額外定義轉換器類了。

我們知道okGo架構預設提供了三種實作convertResponse轉換邏輯的三種convert:

1,StringConverter:按文本解析,解析的編碼依據服務端響應頭中的Content-Type中的編碼格式,自動進行編碼轉換,確定不出現亂碼。

2,BitmapConverter:如果請求的資料是圖檔,則可以使用該轉換器,該方法對圖檔進行了壓縮處理,確定不發生OOM。

3,FileConverter:如果要做檔案下載下傳,可以使用該轉換器,内部封裝了關于檔案下載下傳和進度回調的方法。

CallAdapter詳解

我們寫Rx請求的時候,最後調用了一個adapt()方法,這裡面需要一個CallAdapter擴充卡接口,那麼這個擴充卡是什麼東西呢,主要功能就是将我們得到的Call對象,适配成我們需要的Observable對象。

參考okrx2源碼的目錄結構如下:

安卓項目實戰之強大的網絡請求架構okGo使用詳解(五):擴充項目okRx,完美結合RxJava

在adapter包下,命名規則分為這麼幾組:

開頭的意思:

Observable開頭,表示傳回的對象是Observable對象

安卓項目實戰之強大的網絡請求架構okGo使用詳解(五):擴充項目okRx,完美結合RxJava

其他的:

安卓項目實戰之強大的網絡請求架構okGo使用詳解(五):擴充項目okRx,完美結合RxJava

結尾的意思:

Response結尾,表示傳回對象的泛型是Response

安卓項目實戰之強大的網絡請求架構okGo使用詳解(五):擴充項目okRx,完美結合RxJava

Body結尾,表示傳回對象的泛型是T,沒有外層的Response包裝

安卓項目實戰之強大的網絡請求架構okGo使用詳解(五):擴充項目okRx,完美結合RxJava

Result結尾,表示傳回對象的泛型是Result

安卓項目實戰之強大的網絡請求架構okGo使用詳解(五):擴充項目okRx,完美結合RxJava

OkRx使用緩存

其實關于adapt()方法還有個重載方法:

adapt(AdapterParam param,callAdapter<T,E> adapter)
           

可以額外傳遞一個AdapterParam對象作為第一個參數,我們都知道,okhttp有兩種請求方式,一種是同步請求,一種是異步請求,那麼這個參數就是控制把目前的Call對象适配成Observable時,是使用同步還是異步的方法,如果不傳該參數預設就是使用異步請求,AdapterParam對象隻有一個參數,如下:

安卓項目實戰之強大的網絡請求架構okGo使用詳解(五):擴充項目okRx,完美結合RxJava

如果是使用同步的方法,對應的,我們就使用的是okrx2源碼中的CallExecuteObservable對象來适配,如果是異步,那麼就使用CallEnqueueObservable對象來适配。他們有什麼差別的,其實隻有一個最大的差別,就是緩存的使用。

預設情況下,我們使用的是異步請求來适配的,使用方式和okgo使用緩存一樣,指定cacheKey和cacheMode就行了,如下:

安卓項目實戰之強大的網絡請求架構okGo使用詳解(五):擴充項目okRx,完美結合RxJava

那麼對于okrx緩存回調成功和網絡請求回調成功都是回調onNext()方法,那麼怎麼區分呢,回調的Response對象中有個isFromCache方法,就是表示目前回調是來自緩存還是網絡。

注意事項:

1,不同的緩存模式會導緻onNext()方法具有不同的回調次數,可能一次或者兩次

2, 如果使用同步方法來适配的話,緩存模式CacheMode.FIRST_CACHE_THEN_REQUEST是不生效的,異步才生效,原因是同步請求沒法傳回兩次資料。

取消請求

我們可以在基類BaseActivity中建立這麼兩個方法,把每一個請求的Disposable對象都交給由統一的CompositeDisposable對象去管理。

安卓項目實戰之強大的網絡請求架構okGo使用詳解(五):擴充項目okRx,完美結合RxJava

在Observer對象的onSubscibe方法中,把Disposable添加到CompositeDisposable中:

安卓項目實戰之強大的網絡請求架構okGo使用詳解(五):擴充項目okRx,完美結合RxJava

然後我們在目前activity界面銷毀onDestory方法中或者需要取消的地方調用取消請求的方法:

安卓項目實戰之強大的網絡請求架構okGo使用詳解(五):擴充項目okRx,完美結合RxJava

rxJava請求之map操作符的使用舉例:

map()操作符用于轉換一組資料。至于怎麼轉換,由你自己指定。比如,簡單的對資料進行加減乘除處理。又比如,将某一個類轉成另一個類。又比如,将一組User類對象(userName是User類的一個字段),轉成一組userName對象。

@OnClick(R.id.jsonArrayRequest)
    public void jsonArrayRequest(View view) {
        OkGo.<LzyResponse<List<ServerModel>>>get(Urls.URL_JSONARRAY)//
                .headers("aaa", "111")//
                .params("bbb", "222")//
                .converter(new JsonConvert<LzyResponse<List<ServerModel>>>() {})//
                .adapt(new ObservableBody<LzyResponse<List<ServerModel>>>())//
                .doOnSubscribe(new Consumer<Disposable>() {
                    @Override
                    public void accept(@NonNull Disposable disposable) throws Exception {
                        showLoading();
                    }
                })//
                .map(new Function<LzyResponse<List<ServerModel>>, List<ServerModel>>() {
                    @Override
                    public List<ServerModel> apply(@NonNull LzyResponse<List<ServerModel>> response) throws Exception {
                        return response.data;
                    }
                })//
                .observeOn(AndroidSchedulers.mainThread())//
                .subscribe(new Observer<List<ServerModel>>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        addDisposable(d);
                    }

                    @Override
                    public void onNext(@NonNull List<ServerModel> response) {
                        handleResponse(response);
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        e.printStackTrace();            //請求失敗
                        showToast("請求失敗");
                        handleError(null);
                    }

                    @Override
                    public void onComplete() {
                        dismissLoading();
                    }
                });
    }
           

Observer與Consumer的差別:他們都是充當觀察者角色,後者是簡化了前者,減去了許多回調接口。

Consumer是簡易版的Observer,他有多重重載,可以自定義你需要處理的資訊,我這裡調用的是隻接受onNext消息的方法,他隻提供一個回調接口accept,由于沒有onError和onCompete,無法再 接受到onError或者onCompete之後,實作函數回調。無法回調,并不代表不接收,他還是會接收到onCompete和onError之後做出預設操作,也就是監聽者(Consumer)不在接收 Observable發送的消息,下方的代碼測試了該效果:

final Consumer<String> consumer = new Consumer<String>() {
            @Override
            public void accept(@NonNull String s) throws Exception {
                Log.d("MainActivity", Thread.currentThread().getName() + " String:" + s);
            }
        };
 
        Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
                Log.d("MainActivity", Thread.currentThread().getName() + "emit Hello");
                e.onNext("Hello");
                Log.d("MainActivity", Thread.currentThread().getName() + "emit Complete");
                e.onComplete();
                Log.d("MainActivity", Thread.currentThread().getName() + "emit World");
                e.onNext("World");
            }
        });
           

參考部落格:https://blog.csdn.net/l_o_s/article/details/79409031