前言
在使用 retrofit 的时候,碰到这样一个问题,所有的网络接口都要进行网络请求错误判断而进行错误处理,也就是说每个 Callback 都要做同一件事情,这样就平白添加了许多无用的代码。以下是怎么对 retrofit 的 Callback 进行统一的错误处理
知识了解
retrofit 是对 okHttp 进行的封装,okHttp 请求返回的状态码为:
HTTP Status | 说明 |
---|---|
1xx | 代表请求已被接受,需要继续处理 (临时相应) |
2xx | 代表请求已成功被服务器接收、理解、并接受 |
3xx | 代表需要客户端采取进一步的操作才能完成请求 |
4xx | 代表了客户端看起来可能发生了错误,妨碍了服务器的处理 |
5xx | 表示服务器无法完成明显有效的请求 |
想要知道 HTTP Status 的具体说明请查看网址:HTTP 状态码-维基百科 ,该网址对 HTTP 状态码对每个大状态下各个小状态也进行了详细说明,能够更好的理解 HTTP 的状态码的意义。
优化前
使用过 Retrofit 的网友们,我们都知道,onResponse 方法一般是在网络请求后,有返回信息( HTTP 五类状态码 )时回调;而 onFailure 方法据我了解一般是由于请求延迟、超时,或者网络状态差等网络问题导致请求失败时回调。以下是我们刚接触retrofit时的写法:
UserAPI.signin(entity, new Callback<LoginEntity>() {
@Override
public void onResponse(Call< LoginEntity > call, Response< LoginEntity > response) {
if (response.isSuccessful()){
//1⃣️接口请求成功,对返回的数据进行处理
} else{
//2⃣️对后台返回的请求错误,进行处理
}
}
@Override
public void onFailure(Call<LoginEntity> call, Throwable t) {
super.onFailure(call, t);
//3⃣️对当前网络情况差或者请求超时等网络请求延迟等一些错误处理。
}
});
以上看着没什么问题,但是 isSuccessful() 方法的 HTTP 状态码 是 200 到 300之间,在这之间都算是请求成功;并且在正常情况下只有 200 的时候后台才会返回数据,其他是没有数据的。因此我们还要在1⃣️处还要添加一些判断:
if (200 == response.code()) {
//对后台返回的数据进行处理
} else {
对后台返回200~300之间的错误进行处理
}
而且每个接口都要对2⃣️和3⃣️处每个接口都要这么写,就额外添加了许多无用的重复代码,我们要怎么解决掉这个问题呢,让请求的方法更佳简介,相同的错误可以处理集中处理。以下是我在开发中使用的方法。
优化中——代码实现
使用retrofit异步请求都需要有个 Callback 回调,对请求结果进行处理,我们就重新封装下 Callback。
Callback 是一种 interface,我们不能 extends,也不能在 interface 里面实现功能,它只是一个接口或者说是一种监听。还好在 java 里面提供一个叫抽象类的概念( abstract 关键字修饰),
- 我们先创建一个抽象类 implements Callback<T>;
public abstract class ZHGCallback<T> implements Callback<T> {}
- 在 ZHGCallback 里面创建两个方法:一个抽象方法,一个 protect 方法
public abstract void onSuccessful(Response<T> response);//方法一
protected void onFail(final Call<T> call, Response<T> response) {}//方法二
方法一是请求成功并且请求的 Code 是 200 的回调方法
方法二是统一的错误处理的方法,如果单个接口需要特别处理错误,请重写 onFail 方法
在实现的时候只需要写 onSuccessful(Response response) 方法就行了,如果想要对请求错误进行单独处理,可以重写 onFail() 方法;
- 具体实现如下:
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()){
//解析后台返回的错误信息
ErrorEntity errorEntity = new ErrorEntity();
try {
errorEntity = ErrorEntity.parse(response.errorBody().string());
} catch (IOException e) {
Log.e(TAG, "ErrorEntity解析错误:" + e.getMessage());
}
String message;
if (errorEntity.getErrorMessage() != null) {
message = errorEntity.getErrorMessage();
}else {
message ="账号已过期,请重新登录";
}
// errorEntity.getErrorCode() 获取后台返回的 errorCode,根据 errorCode 前端做相应的处理
}
}
}
代码使用
我们以登录接口为例,一步一步实现网络请求。
- 网络请求接口和方法的的定义
定义一个类,按照 retrofit 的使用说明,定义请求方式及方法
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);
}
}
- 网络请求的实现:
在请求的时候,我们直接使用我们定义的 ZHGCallback ,它会默认实现 onSuccessful 方法,onFail 方法在我们需要对错误单独处理时,重写就可以了。
UserAPI.signin(entity, new ZHGCallback<LoginEntity>() {
@Override
public void onSuccessful(Response<LoginEntity> response) {
// 返回 200 ,请求成功,对数据进行处理
}
//⚠️如果对错误没有特殊处理,可以省略 onFail 方法;如果有特殊处理,重写 onFail 方法
@Override
protected void onFail(Call<T> call , Throwable t, Response<T> response) {
super.onFail(call, t, response);
}
});
总结
对错误返回统一处理,大大的节省了代码量,并且可以很方便的修改错误信息,对网络请求管理更加便捷。现在大多数人都在使用 Rxjava+retrofit 进行网络请求,它逻辑清晰,代码实现起来更加方便,接下来,开始着手准备 Rx 的学习和整理。