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)容判斷,判斷一次是否為空。