前言
在使用 retrofit 的時(shí)候,碰到這樣一個(gè)問(wèn)題,所有的網(wǎng)絡(luò)接口都要進(jìn)行網(wǎng)絡(luò)請(qǐng)求錯(cuò)誤判斷而進(jìn)行錯(cuò)誤處理,也就是說(shuō)每個(gè) Callback 都要做同一件事情,這樣就平白添加了許多無(wú)用的代碼。以下是怎么對(duì) retrofit 的 Callback 進(jìn)行統(tǒng)一的錯(cuò)誤處理
知識(shí)了解
retrofit 是對(duì) okHttp 進(jìn)行的封裝,okHttp 請(qǐng)求返回的狀態(tài)碼為:
| HTTP Status | 說(shuō)明 |
|---|---|
| 1xx | 代表請(qǐng)求已被接受,需要繼續(xù)處理 (臨時(shí)相應(yīng)) |
| 2xx | 代表請(qǐng)求已成功被服務(wù)器接收、理解、并接受 |
| 3xx | 代表需要客戶端采取進(jìn)一步的操作才能完成請(qǐng)求 |
| 4xx | 代表了客戶端看起來(lái)可能發(fā)生了錯(cuò)誤,妨礙了服務(wù)器的處理 |
| 5xx | 表示服務(wù)器無(wú)法完成明顯有效的請(qǐng)求 |
想要知道 HTTP Status 的具體說(shuō)明請(qǐng)查看網(wǎng)址:HTTP 狀態(tài)碼-維基百科 ,該網(wǎng)址對(duì) HTTP 狀態(tài)碼對(duì)每個(gè)大狀態(tài)下各個(gè)小狀態(tài)也進(jìn)行了詳細(xì)說(shuō)明,能夠更好的理解 HTTP 的狀態(tài)碼的意義。
優(yōu)化前
使用過(guò) Retrofit 的網(wǎng)友們,我們都知道,onResponse 方法一般是在網(wǎng)絡(luò)請(qǐng)求后,有返回信息( HTTP 五類狀態(tài)碼 )時(shí)回調(diào);而 onFailure 方法據(jù)我了解一般是由于請(qǐng)求延遲、超時(shí),或者網(wǎng)絡(luò)狀態(tài)差等網(wǎng)絡(luò)問(wèn)題導(dǎo)致請(qǐng)求失敗時(shí)回調(diào)。以下是我們剛接觸retrofit時(shí)的寫法:
UserAPI.signin(entity, new Callback<LoginEntity>() {
@Override
public void onResponse(Call< LoginEntity > call, Response< LoginEntity > response) {
if (response.isSuccessful()){
//1??接口請(qǐng)求成功,對(duì)返回的數(shù)據(jù)進(jìn)行處理
} else{
//2??對(duì)后臺(tái)返回的請(qǐng)求錯(cuò)誤,進(jìn)行處理
}
}
@Override
public void onFailure(Call<LoginEntity> call, Throwable t) {
super.onFailure(call, t);
//3??對(duì)當(dāng)前網(wǎng)絡(luò)情況差或者請(qǐng)求超時(shí)等網(wǎng)絡(luò)請(qǐng)求延遲等一些錯(cuò)誤處理。
}
});
以上看著沒(méi)什么問(wèn)題,但是 isSuccessful() 方法的 HTTP 狀態(tài)碼 是 200 到 300之間,在這之間都算是請(qǐng)求成功;并且在正常情況下只有 200 的時(shí)候后臺(tái)才會(huì)返回?cái)?shù)據(jù),其他是沒(méi)有數(shù)據(jù)的。因此我們還要在1??處還要添加一些判斷:
if (200 == response.code()) {
//對(duì)后臺(tái)返回的數(shù)據(jù)進(jìn)行處理
} else {
對(duì)后臺(tái)返回200~300之間的錯(cuò)誤進(jìn)行處理
}
而且每個(gè)接口都要對(duì)2??和3??處每個(gè)接口都要這么寫,就額外添加了許多無(wú)用的重復(fù)代碼,我們要怎么解決掉這個(gè)問(wèn)題呢,讓請(qǐng)求的方法更佳簡(jiǎn)介,相同的錯(cuò)誤可以處理集中處理。以下是我在開(kāi)發(fā)中使用的方法。
優(yōu)化中——代碼實(shí)現(xiàn)
使用retrofit異步請(qǐng)求都需要有個(gè) Callback 回調(diào),對(duì)請(qǐng)求結(jié)果進(jìn)行處理,我們就重新封裝下 Callback。
Callback 是一種 interface,我們不能 extends,也不能在 interface 里面實(shí)現(xiàn)功能,它只是一個(gè)接口或者說(shuō)是一種監(jiān)聽(tīng)。還好在 java 里面提供一個(gè)叫抽象類的概念( abstract 關(guān)鍵字修飾),
- 我們先創(chuàng)建一個(gè)抽象類 implements Callback<T>;
public abstract class ZHGCallback<T> implements Callback<T> {} - 在 ZHGCallback 里面創(chuàng)建兩個(gè)方法:一個(gè)抽象方法,一個(gè) protect 方法
public abstract void onSuccessful(Response<T> response);//方法一
protected void onFail(final Call<T> call, Response<T> response) {}//方法二
方法一是請(qǐng)求成功并且請(qǐng)求的 Code 是 200 的回調(diào)方法
方法二是統(tǒng)一的錯(cuò)誤處理的方法,如果單個(gè)接口需要特別處理錯(cuò)誤,請(qǐng)重寫 onFail 方法
在實(shí)現(xiàn)的時(shí)候只需要寫 onSuccessful(Response response) 方法就行了,如果想要對(duì)請(qǐng)求錯(cuò)誤進(jìn)行單獨(dú)處理,可以重寫 onFail() 方法;
- 具體實(shí)現(xiàn)如下:
public abstract class ZHGCallback<T> implements Callback<T>{
private String TAG = this.getClass().getSimpleName()+">>>>";
@Override
public void onResponse(Call<T> call, Response<T> response) {
if (200 == response.code()){
onSuccessful(call,response);
}else {
onFail(call,null,response);
}
}
@Override
public void onFailure(Call<T> call, Throwable t) {
onFail(call,t,null);
}
public abstract void onSuccessful(Call<T> call, Response<T> response);
protected void onFail(Call<T> call , Throwable t, Response<T> response){
if (null == response){
Toast.makeText(BaseApplication.getContext(),t.toString(),Toast.LENGTH_SHORT).show();
return;
}
Log.e(TAG,"RESPONSE code is "+response.code()+": "+ response.raw().toString());
if (null != response.errorBody()){
//解析后臺(tái)返回的錯(cuò)誤信息
ErrorEntity errorEntity = new ErrorEntity();
try {
errorEntity = ErrorEntity.parse(response.errorBody().string());
} catch (IOException e) {
Log.e(TAG, "ErrorEntity解析錯(cuò)誤:" + e.getMessage());
}
String message;
if (errorEntity.getErrorMessage() != null) {
message = errorEntity.getErrorMessage();
}else {
message ="賬號(hào)已過(guò)期,請(qǐng)重新登錄";
}
// errorEntity.getErrorCode() 獲取后臺(tái)返回的 errorCode,根據(jù) errorCode 前端做相應(yīng)的處理
}
}
}
代碼使用
我們以登錄接口為例,一步一步實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求。
- 網(wǎng)絡(luò)請(qǐng)求接口和方法的的定義
定義一個(gè)類,按照 retrofit 的使用說(shuō)明,定義請(qǐng)求方式及方法
public class UserAPI {
private static final String API_URL = ApiConstant.Service_API + "users/";
interface UserInterface {
// 登錄
@POST("signin")
Call<LoginEntity> signIn(@Body SigninParameterEntity signinParameterEntity);
}
// 使用用戶名密碼登錄
public static void signin(final SigninParameterEntity signinParameterEntity, final ZHGCallback<LoginEntity> callback) {
Retrofit retrofit = RetrofitUtil.retrofitClient(API_URL);
UserInterface userInterface = retrofit.create(UserInterface.class);
userInterface.signIn(signinParameterEntity).enqueue(callback);
}
}
- 網(wǎng)絡(luò)請(qǐng)求的實(shí)現(xiàn):
在請(qǐng)求的時(shí)候,我們直接使用我們定義的 ZHGCallback ,它會(huì)默認(rèn)實(shí)現(xiàn) onSuccessful 方法,onFail 方法在我們需要對(duì)錯(cuò)誤單獨(dú)處理時(shí),重寫就可以了。
UserAPI.signin(entity, new ZHGCallback<LoginEntity>() {
@Override
public void onSuccessful(Response<LoginEntity> response) {
// 返回 200 ,請(qǐng)求成功,對(duì)數(shù)據(jù)進(jìn)行處理
}
//??如果對(duì)錯(cuò)誤沒(méi)有特殊處理,可以省略 onFail 方法;如果有特殊處理,重寫 onFail 方法
@Override
protected void onFail(Call<T> call , Throwable t, Response<T> response) {
super.onFail(call, t, response);
}
});
總結(jié)
對(duì)錯(cuò)誤返回統(tǒng)一處理,大大的節(jié)省了代碼量,并且可以很方便的修改錯(cuò)誤信息,對(duì)網(wǎng)絡(luò)請(qǐng)求管理更加便捷。現(xiàn)在大多數(shù)人都在使用 Rxjava+retrofit 進(jìn)行網(wǎng)絡(luò)請(qǐng)求,它邏輯清晰,代碼實(shí)現(xiàn)起來(lái)更加方便,接下來(lái),開(kāi)始著手準(zhǔn)備 Rx 的學(xué)習(xí)和整理。