Retrofit使用技巧

Retrofit 配合 RxJava 的使用是越來越廣泛,小到個人項目,大到公司項目,都能看到它,它的使用也是挺簡單的,它本身就是對 OkHttp 的一個封裝,讓開發(fā)者在使用網(wǎng)絡(luò)請求時更加方便、快捷。我用了一段時間之后,覺得雖然封裝的挺好的,但是在用到一些東西的時候還是需要來自定義一下的,下面就來分享一下,我在使用過程中的一些自定義小功能。

Retrofit 的使用

連接超時

平時對連接超時沒什么印象,因為你即使不設(shè)置,默認(rèn)情況下也是有超時時長的,如果想要設(shè)置連接超時時長的話,需要在 OkHttpClient.Builder 的初始化的時候進(jìn)行設(shè)置。例如:

        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .connectTimeout(Mark.HTTP_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)
                .readTimeout(Mark.HTTP_READ_TIMEOUT, TimeUnit.MILLISECONDS)
                .writeTimeout(Mark.HTTP_WRITE_TIMEOUT, TimeUnit.MILLISECONDS);
                

在這里我設(shè)置了三個連接超時的時長,分別是:

  • connectTimeout 是 TCP Socket 的三次握手的時長,在這個時間范圍內(nèi)進(jìn)行 3 次握手;
  • readTimeout 是 TCP Socket 的三次握手和單獨讀取 IO 操作的時長,包括響應(yīng)的來源,如果在這個過程中連接失敗,則獲取不到數(shù)據(jù);
  • writeTimeout 則是用于 IO 寫入的超時限制。

從 Reftofit 2.5.0 的版本開始,這三個的默認(rèn)連接超時時長均為 10 秒。

參考地址

公共參數(shù)攔截器

在一些情況下,我們需要在請求上添加一些公共信息,比如,用戶登錄之后攜帶的驗證信息,或是針對不同的請求地址加上一些固有的請求參數(shù)。要做到這一點就需要把一些公共的信息提取出來,放在一個攔截器中,之后每一次的網(wǎng)絡(luò)請求根據(jù)限制條件進(jìn)行判斷是否使用參數(shù)連接器對請求地址或頭部信息進(jìn)行二次改造。

Interceptor mTokenInterceptor = new Interceptor() {
    @Override public Response intercept(Chain chain) throws IOException {
        Request originalRequest = chain.request();
        if (Your.sToken == null || alreadyHasAuthorizationHeader(originalRequest)) {
            return chain.proceed(originalRequest);
        }
        Request authorised = originalRequest.newBuilder()
            .header("Authorization", Your.sToken)
            .build();
        return chain.proceed(authorised);
    }
};

或是

Interceptor mTokenInterceptor = new Interceptor() {
    @Override public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();
        HttpUrl originalHttpUrl = original.url();
        HttpUrl url = originalHttpUrl.newBuilder()
                            .addQueryParameter("accountsuite", "someThing")
                            .build();
        return chain.proceed(authorised);
    }
};

設(shè)置攔截器之后,需要在 OkHttpClient.Builder 上進(jìn)行應(yīng)用,通過這個方法.addInterceptor(mTokenInterceptor)加上即可,而且 OkHttp 的攔截器可以同時設(shè)置多個,比如在添加參數(shù)連接器之后,再加上下面的日志攔截器。

參考地址

網(wǎng)絡(luò)請求日志

網(wǎng)絡(luò)請求日志輸出是非常重要的,在調(diào)試的時候能及時的查看客戶端與后臺的數(shù)據(jù)交互是否存在異常??墒?,我在第一次使用的時候是不知道該怎么去配置,看了文檔才知道可以自己定義一個 HttpLoggingInterceptor(日志攔截器) 然后設(shè)置日志攔截等級并像上面那樣給添加到 OkHttpClient.Builder 即可,HttpLoggingInterceptor 一共有 4 個等級:

  • NONE 不打印
  • BASIC 只打印基礎(chǔ)信息
    • 請求方法類型(GET、POST……)
    • HTTP 版本(HTTP1.0/HTTP1.1)
    • 請求內(nèi)容體大小
    • 是否成功返回
    • 耗時時長
    • 內(nèi)容體大小
  • HEADERS 在 BASIC 級別的基礎(chǔ)上增加請求 HEADER 信息
  • BODY 在 HEADERS 級別的基礎(chǔ)上增加請求及返回的 BODY 信息

OkHttp 設(shè)置網(wǎng)絡(luò)日志請求攔截器

        HttpLoggingInterceptor loggingInterceptor=new HttpLoggingInterceptor();
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BASIC);
        
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(CONNECT_TIME_OUT, TimeUnit.SECONDS)
                .readTimeout(CONNECT_TIME_OUT, TimeUnit.SECONDS)
                .writeTimeout(CONNECT_TIME_OUT, TimeUnit.SECONDS)
                .addInterceptor(loggingInterceptor)
                .build();

其實,這四個等級已經(jīng)能滿足需求,不過,由于是使用 系統(tǒng)的 log 打印模塊,每次只能把單個信息打印出來,而且還不能定位到具體的行數(shù)以及線程,真的不方便。

所以,這個時候就需要自己動手去改造原有的 OkHttp 的日志打印,不過我們想要的日志內(nèi)容基本上是全覆蓋了 HttpLoggingInterceptor 的后三個等級。所以,可以參考著他的源碼來進(jìn)行自己修改。
我想要達(dá)到的效果就是取消等級限制并使用第三方的日志輸出統(tǒng)一打?。?/p>

話不多說,上代碼:

    private static Interceptor logInterceptor() {
        Interceptor logInterceptor = new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request original = chain.request();
                Request.Builder requestBuilder = original.newBuilder();
                Request request = requestBuilder.url(original.url()).build();

                RequestBody requestBody = request.body();
                boolean hasRequestBody = requestBody != null;

                StringBuilder requestSb = new StringBuilder();
                Connection connection = chain.connection();
                Protocol protocol = connection != null ? connection.protocol() : Protocol.HTTP_1_1;
                requestSb.append("請求-->")
                        .append(' ')
                        .append(request.method())
                        .append(' ')
                        .append(request.url())
                        .append(' ')
                        .append(protocol)
                        .append("\n");

                if (hasRequestBody) {
                    if (requestBody.contentType() != null) {
                        requestSb.append("Content-Type: ")
                                .append(requestBody.contentType())
                                .append("\n");
                    }
                    if (requestBody.contentLength() != -1) {
                        requestSb.append("Content-Length: ")
                                .append(requestBody.contentLength())
                                .append("-byte body").append("\n");
                    }
                }

                Headers requestHeaders = request.headers();
                for (int i = 0, count = requestHeaders.size(); i < count; i++) {
                    String name = requestHeaders.name(i);
                    requestSb.append(name)
                            .append(": ")
                            .append(requestHeaders.value(i));
                    requestSb.append("\n");
                }

                if (hasRequestBody) {
                    Buffer buffer = new Buffer();
                    requestBody.writeTo(buffer);

                    Charset charset = UTF8;
                    MediaType contentType = requestBody.contentType();
                    if (contentType != null) {
                        charset = contentType.charset(UTF8);
                    }
                    if (isPlaintext(buffer)) {
                        requestSb.append(buffer.readString(charset))
                                .append("\n");
                        requestSb.append("--> END ").
                                append(request.method());
                    } else {
                        requestSb.append("--> END ")
                                .append(request.method())
                                .append(" (binary ")
                                .append(requestBody.contentLength())
                                .append("-byte body omitted)");
                    }
                }
                Logger.i(requestSb.toString());

                long startNs = System.nanoTime();
                Response response;
                try {
                    response = chain.proceed(request);
                } catch (Exception e) {
                    Logger.e("<-- HTTP FAILED: " + e);
                    throw e;
                }

                long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);
                ResponseBody responseBody = response.body();
                BufferedSource source = null;
                Buffer buffer = null;
                int responseCode = response.code();
                if (responseBody != null) {
                    source = responseBody.source();
                    source.request(Long.MAX_VALUE);
                    buffer = source.buffer();
                }
                long contentLength = responseBody.contentLength();

                StringBuilder responseSb = new StringBuilder();
                responseSb.append("返回<-- ")
                        .append(response.code())
                        .append(' ')
                        .append(response.message())
                        .append(' ')
                        .append(response.request().url())
                        .append(" (")
                        .append(tookMs)
                        .append("ms").append(')')
                        .append("\n");

                Headers headers = response.headers();
                for (int i = 0, count = headers.size(); i < count; i++) {
                    responseSb.append(headers.name(i))
                            .append(": ")
                            .append(headers.value(i))
                            .append("\n");
                }
                Charset charset = UTF8;
                MediaType contentType = responseBody.contentType();
                if (contentType != null) {
                    try {
                        charset = contentType.charset(UTF8);
                    } catch (UnsupportedCharsetException e) {
                        Logger.i("Couldn't decode the response body; charset is likely malformed.");
                        Logger.i("<-- END HTTP");
                        return response;
                    }
                }
                if (!isPlaintext(buffer)) {
                    Logger.i("<-- END HTTP (binary " + buffer.size() + "-byte body omitted)");
                    return response;
                }

                if (contentLength != 0) {
                    Logger.i("返回數(shù)據(jù): " + buffer.clone().readString(charset));
                }

                responseSb.append("<-- END HTTP (")
                        .append(buffer.size())
                        .append("-byte body)");
                Logger.i(responseSb.toString());

                return response;
            }
        };
        return logInterceptor;
    }

    private static boolean isPlaintext(Buffer buffer) {
        try {
            Buffer prefix = new Buffer();
            long byteCount = buffer.size() < 64 ? buffer.size() : 64;
            buffer.copyTo(prefix, 0, byteCount);
            for (int i = 0; i < 16; i++) {
                if (prefix.exhausted()) {
                    break;
                }
                int codePoint = prefix.readUtf8CodePoint();
                if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) {
                    return false;
                }
            }
            return true;
        } catch (EOFException e) {
            return false;
        }
    }

代碼雖然有些長,但還是很容易理解。就是分別將 Request 以及 Response 進(jìn)行攔截,得到想展示出來的內(nèi)容信息,然后拼接起來,最后使用 Logger 進(jìn)行打印。打印出來的效果還是比較不錯的。在這里攔截到 Response 之后,我把所有的異常統(tǒng)一進(jìn)行捕捉了,還可以添加一些其他的異常信息,比如:連接超時的異常、URL 錯誤的異常等等。

主要就是參考 OkHttp 里的 HttpLoggingInterceptor 這個類,可以自己嘗試一下。

  • 請求打印
01-30 11:09:55.085 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ╔════════════════════════════════════════════════════════════════════════════════════════
01-30 11:09:55.086 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║ Thread: RxCachedThreadScheduler-6
01-30 11:09:55.086 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ╟────────────────────────────────────────────────────────────────────────────────────────
01-30 11:09:55.086 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║ RealInterceptorChain.proceed  (RealInterceptorChain.java:67)
01-30 11:09:55.086 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║    RealInterceptorChain.proceed  (RealInterceptorChain.java:92)
01-30 11:09:55.086 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║       NetWorkManager$4.intercept  (NetWorkManager.java:288)
01-30 11:09:55.086 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ╟────────────────────────────────────────────────────────────────────────────────────────
01-30 11:09:55.086 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║ 請求--> POST http://192.168.199.186:8080/report/api/v1/drp/checkInputBill/create?accountsuite=demo http/1.1
01-30 11:09:55.086 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║ Content-Type: application/json; charset=UTF-8
01-30 11:09:55.086 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║ Content-Length: 1576-byte body
01-30 11:09:55.086 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║ Conteng-type: application/json;charset=UTF-8
01-30 11:09:55.086 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║ Authorization: Basic YWRtaW46MTExMTEx
01-30 11:09:55.086 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║ {"checkInputBill":[{"createOperatorName":"admin","createOperatorCode":"admin","handWorkBill":"4001","checkNoticeBillId":"31e4fb9dd3b441dea77904ec9a435b7e","checkInputBillItems":[{"quantity":"1","barCode1":"0001V002201","sizeName":"XS","skuIds":"4028471e6116e54201611c4311070062","productCode":"0001V","colorName":"米紅","barCode2":"0001V002201"},{"quantity":"1","barCode1":"0010003","sizeName":"165/92A","skuIds":"aaf9426940bb5b7b0140bee72e873f5e","productCode":"001首飾","colorName":"均色","barCode2":"0010003"},{"quantity":"1","barCode1":"000DX0039","sizeName":"160/88A","skuIds":"4028810c5b88f46c015b896754810002","productCode":"0040Z","colorName":"純白","barCode2":"0040Z0102"},{"quantity":"4","barCode1":"000DY0340","sizeName":"165/92A","skuIds":"4028810c5b88f46c015b896754820006","productCode":"0040Z","colorName":"米白","barCode2":"0040Z0203"},{"quantity":"1","barCode1":"000DY0539","sizeName":"170/96A","skuIds":"4028810c5b88f46c015b896754820007","productCode":"0040Z","colorName":"米白","barCode2":"0040Z0204"},{"quantity":"2","barCode1":"1030620027103","sizeName":"165/92A","skuIds":"aaf9426948850ec40148893130014f7c","productCode":"杏色V領(lǐng)下擺紗衫","colorName":"淺杏","barCode2":"null"}],"createOperatorId":"40288996207b57eb01207b5c81ee0004","remark":"4001:4001","updateTime":"2018-01-12 16:42:38","createTime":"2018-01-12 15:29:49","backGroundColorId":"1","checkNoticeBill":"PDT18011100009","checkInputBillId":"dc1c7d1d3b454da3903e0beec7da2e8f"}],"checkType":1,"checkTime":"2018-02-01 02:30:00","operatorId":"40288996207b57eb01207b5c81ee0004"}
01-30 11:09:55.086 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║ --> END POST
01-30 11:09:55.086 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ╚════════════════════════════════════════════════════════════════════════════════════════
  • 結(jié)果打印
01-30 11:09:55.264 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ╔════════════════════════════════════════════════════════════════════════════════════════
01-30 11:09:55.265 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║ Thread: RxCachedThreadScheduler-6
01-30 11:09:55.265 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ╟────────────────────────────────────────────────────────────────────────────────────────
01-30 11:09:55.265 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║ RealInterceptorChain.proceed  (RealInterceptorChain.java:67)
01-30 11:09:55.265 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║    RealInterceptorChain.proceed  (RealInterceptorChain.java:92)
01-30 11:09:55.266 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║       NetWorkManager$4.intercept  (NetWorkManager.java:386)
01-30 11:09:55.266 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ╟────────────────────────────────────────────────────────────────────────────────────────
01-30 11:09:55.266 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║ 返回數(shù)據(jù): {"result":true,"checkInputBill":[{"createOperatorName":"admin","createOperatorCode":"admin","handWorkBill":"4001","checkNoticeBillId":"31e4fb9dd3b441dea77904ec9a435b7e","checkInputBillItems":[{"quantity":"1","barCode1":"0001V002201","sizeName":"XS","skuIds":"4028471e6116e54201611c4311070062","productCode":"0001V","colorName":"米紅","barCode2":"0001V002201"},{"quantity":"1","barCode1":"0010003","sizeName":"165/92A","skuIds":"aaf9426940bb5b7b0140bee72e873f5e","productCode":"001首飾","colorName":"均色","barCode2":"0010003"},{"quantity":"1","barCode1":"000DX0039","sizeName":"160/88A","skuIds":"4028810c5b88f46c015b896754810002","productCode":"0040Z","colorName":"純白","barCode2":"0040Z0102"},{"quantity":"4","barCode1":"000DY0340","sizeName":"165/92A","skuIds":"4028810c5b88f46c015b896754820006","productCode":"0040Z","colorName":"米白","barCode2":"0040Z0203"},{"quantity":"1","barCode1":"000DY0539","sizeName":"170/96A","skuIds":"4028810c5b88f46c015b896754820007","productCode":"0040Z","colorName":"米白","barCode2":"0040Z0204"},{"quantity":"2","barCode1":"1030620027103","sizeName":"165/92A","skuIds":"aaf9426948850ec40148893130014f7c","productCode":"杏色V領(lǐng)下擺紗衫","colorName":"淺杏","barCode2":"null"}],"createOperatorId":"40288996207b57eb01207b5c81ee0004","remark":"4001:4001","updateTime":"2018-01-12 16:42:38","createTime":"2018-01-12 15:29:49","backGroundColorId":"1","checkNoticeBill":"PDT18011100009","checkInputBillId":"dc1c7d1d3b454da3903e0beec7da2e8f","method":"update"}]}
01-30 11:09:55.266 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ╚════════════════════════════════════════════════════════════════════════════════════════
01-30 11:09:55.266 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ╔════════════════════════════════════════════════════════════════════════════════════════
01-30 11:09:55.267 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║ Thread: RxCachedThreadScheduler-6
01-30 11:09:55.267 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ╟────────────────────────────────────────────────────────────────────────────────────────
01-30 11:09:55.267 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║ RealInterceptorChain.proceed  (RealInterceptorChain.java:67)
01-30 11:09:55.267 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║    RealInterceptorChain.proceed  (RealInterceptorChain.java:92)
01-30 11:09:55.267 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║       NetWorkManager$4.intercept  (NetWorkManager.java:390)
01-30 11:09:55.267 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ╟────────────────────────────────────────────────────────────────────────────────────────
01-30 11:09:55.267 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║ 返回<-- 200 OK http://192.168.199.186:8080/report/api/v1/drp/checkInputBill/create?accountsuite=demo (176ms)
01-30 11:09:55.267 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║ Content-Type: application/json;charset=UTF-8
01-30 11:09:55.267 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║ Transfer-Encoding: chunked
01-30 11:09:55.267 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║ Server: Jetty(7.6.14.v20131031)
01-30 11:09:55.267 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║ Cache-Control: public, max-age=60
01-30 11:09:55.267 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ║ <-- END HTTP (1512-byte body)
01-30 11:09:55.267 24755-29465/com.soooft.android.baicaipos I/BaiCaiPOS: ╚════════════════════════════════════════════════════════════════════════════════════════

可以看到 Logger 打印的內(nèi)容還是挺豐富的,包含了行號,線程再加上那個范圍框,更能直觀的看出日志內(nèi)容。

與 RxJava 相結(jié)合

現(xiàn)在網(wǎng)絡(luò)請求都是 Retrofit 配合 RxJava ,針對 RxJava 有兩點可以進(jìn)行優(yōu)化改進(jìn)的地方。

IO 線程與 Android 主線程的切換

要知道在 Android 中是不能將耗時操作放在主線程的,以前自己通過 Thread + HttpURLConnection 實現(xiàn)網(wǎng)絡(luò)請求的時候使用的是 Handler 進(jìn)行處理線程切換,現(xiàn)在換成了 RxJava 就更方便了,不過,每次都要寫那兩行去切換線程,雖然就那么兩行,但也還是不想寫。

RxJava 有一個操作符 compose() 異常的強(qiáng)大,可以在保持原有 RxJava 編程風(fēng)格不變的情況下完成自定義的操作。 ObservableTransformer 是 RxJava 中一個強(qiáng)大的接口,用于將類型 A 轉(zhuǎn)換成類型 B ,這么說有些牽強(qiáng)了,其實就是把上游的內(nèi)容經(jīng)過 ObservableTransformer 轉(zhuǎn)換成下游想要的類型,當(dāng)然如果類型不變,也是可以進(jìn)行的或是進(jìn)行一些操作。

這里就需要結(jié)合 compose 和 ObservableTransformer 來一起使用,看代碼吧。

    public static <T> ObservableTransformer<T, T> applySchedulers() {
        return new ObservableTransformer<T, T>() {
            @Override
            public ObservableSource<T> apply(Observable<T> upstream) {
                return upstream.subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread());
            }
        };
    }

當(dāng)然,如果習(xí)慣用 Java 8 的 Lambda 表達(dá)式,看起來就更簡潔了。簡潔是挺簡潔的,不過有些不熟悉的方法,就完全不知道什么意思了,像我這樣的新手還是不用的好。

    public static <T> ObservableTransformer<T, T> applySchedulers() {
        return upstream -> upstream.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }

網(wǎng)絡(luò)數(shù)據(jù)封裝

在實際的開發(fā)過程中,基本上服務(wù)器返回的內(nèi)容都是這樣的:

{
    resultNo: 200,
    message: "成功"
    result: [],
    error: false
}

這樣的返回信息,包含了一些狀態(tài)信息及具體的數(shù)據(jù),其中 resultNo 和 message 以及 error 都是類型不會變的狀態(tài)信息,只有其中的 result 是會動態(tài)變化的具體數(shù)據(jù),可能里面是一個 List 也可能里面是一個 布爾值變量,甚至還有可能嵌套好幾層。所以可以把 result 定義為泛型 T ,這樣在具體到單一個接口數(shù)據(jù)的時候再指定類型即可。

public class BaseResponse<T> {
    private boolean error;
    private T results;

    /*
     * get and set 
     */
}

如果是這樣的話,我們在定義網(wǎng)絡(luò)接口的時候,就可以指明實際返回的數(shù)據(jù)類型了。例如:

    @GET("data/{type}/{size}/{page}")
    Observable<BaseResponse<List<Map<String, Object>>>> typeData(@Path("type") String type, @Path("size") int size, @Path("page") int page);

不過,這樣使用了 BaseResponse<T> 之后,在 Observable 實現(xiàn)訂閱( subscribe )的時候,提供的參數(shù)類型也就成了 BaseResponse<List<Map<String, Object>>> response ,這時候,需要我們從 response 中再取一次,多寫一行?不可能的。

上面在進(jìn)行線程切換的時候,用到了 ObservableTransformer 這里也可以用,上面是相同的事件類型使用它來進(jìn)行轉(zhuǎn)換,只不過現(xiàn)在變成了,不同類型的數(shù)據(jù)轉(zhuǎn)換。

    public static <T> ObservableTransformer<BaseResponse<T>, T> handleResult() {
        return new ObservableTransformer<BaseResponse<T>, T>() {
            @Override
            public ObservableSource<T> apply(Observable<BaseResponse<T>> upstream) {
                return upstream.flatMap(new Function<BaseResponse<T>, ObservableSource<T>>() {
                    @Override
                    public ObservableSource<T> apply(BaseResponse<T> response) throws Exception {
                        if (response == null) {
                            return Observable.empty();
                        } else if (response.getResults() == null) {
                            return Observable.empty();
                        } else {
                            return Observable.just(response.getResults());
                        }
                    }
                });
            }
        };
    }

同樣的,實現(xiàn) ObservableTransformer 中的 apply() 方法,這時候就不是簡單的線程切換了,而是需要進(jìn)行類型之間的轉(zhuǎn)換。這里我只是簡單的進(jìn)行類型轉(zhuǎn)換,其實還可以加入一些簡單的邏輯判斷。在這里,我們已經(jīng)可以獲取到 BaseResponse 了,那么我們可以根據(jù)其中的一些公共內(nèi)容進(jìn)行判斷,然后進(jìn)行發(fā)射(RxJava)不同的事件,比如,跟后臺開發(fā)約定好一些錯誤代碼,如 404 ,那么在這里,就可以加入 針對 404 的事件處理,可以是 發(fā)射一個自定義異?;蚴瞧渌牟僮?;也可以是針對返回的 result 進(jìn)行內(nèi)容判斷,判斷一次是否為空。

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

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,872評論 25 709
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,533評論 19 139
  • 李茂書法
    洗墨人閱讀 173評論 0 1
  • 當(dāng)我發(fā)現(xiàn)Ego潛入頭腦世界,感覺被它困在監(jiān)獄中,被它戲弄,帶我遛彎到未來世界中。突然,驚醒,力量奪回!這種決斗,奇妙!
    芯儀優(yōu)品閱讀 197評論 0 0
  • 2017年12月13日 星期三 晴 【故事】 當(dāng)石頭城全城再次響起防空警報聲時,豐子的車剛從那座雕塑前駛過,就是...
    木徒閱讀 686評論 3 0

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