前言
最近对Retrofit访问网络回调进行改进,主要统一后台API接口Json返回格式,错误提示模糊化。
一、统一后台台返回数据格式
{
"code": 0,
"data": {},
"message": "msg"
}
public class BaseCallModel<T> {
public int code;
public String message;
public T data;
}
二、例子
这里使用玩安卓开发API测试一波,感谢玩安卓!
1.返回Json
{
"data": [
{
"children": [],
"courseId": 13,
"id": 408,
"name": "鸿洋",
"order": 190000,
"parentChapterId": 407,
"userControlSetTop": false,
"visible": 1
},
{
"children": [],
"courseId": 13,
"id": 409,
"name": "郭霖",
"order": 190001,
"parentChapterId": 407,
"userControlSetTop": false,
"visible": 1
}
],
"errorCode": 0,
"errorMsg": ""
}
2.Model
public class BaseCallModel<T> {
private int errorCode;
private String errorMsg;
private T data;
}
public interface ApiService {
@GET("/wxarticle/chapters/json")
Call<BaseCallModel<List<WxArticle>>> getWxArticle();
}
3.以前的CallBack使用
ApiClient.getInstance().getService().getWxArticle().enqueue(new CallBack1<BaseCallModel<List<WxArticle>>>() {
@Override
public void success(BaseCallModel<List<WxArticle>> baseCallModel) {
if (baseCallModel.getErrorCode() == SUCCESS_CODE) {
①setData(baseCallModel.getData());
} else {
②Toast.makeText(CallBackTestActivity.this, baseCallModel.getErrorMsg(), Toast.LENGTH_SHORT).show();
}
}
@Override
public void failure(String msg) {
③Toast.makeText(CallBackTestActivity.this, msg, Toast.LENGTH_SHORT).show();
}
});
4.需求分析
这里①是获取服务器返回的数据,②
和③大部分都是错误输出提示 少部分根据code做出不同的业务处理。
三、封装CallBack
根据需求我抽象出三个方法,
// 访问服务器成功直接获取数据
public abstract void success(T t);
// 服务器错误返回code 和message
public abstract void failure(int code,String msg);
// 其他错误
public abstract void error(String msg);
CallBack实现
public abstract class CallBack<T> implements Callback<BaseCallModel<T>> {
public static final int SUCCESS_CODE = 0;
public abstract void success(T t);
public abstract void failure(int code, String msg);
public abstract void error(String msg);
@Override
public void onResponse(Call<BaseCallModel<T>> call, Response<BaseCallModel<T>> response) {
if (response.isSuccessful() && response.body() != null) {
if (response.body().getErrorCode() == SUCCESS_CODE) {
success(response.body().getData());
} else {
failure(response.body().getErrorCode()response.body().getErrorMsg());
}
}
// other
}
@Override
public void onFailure(Call<BaseCallModel<T>> call, Throwable t) {
if (t instanceof SocketTimeoutException) {//超时
error(t.getMessage());
} else if (t instanceof ConnectException) {//连接错误
error(t.getMessage());
} else if (t instanceof UnknownError) { //未找到主机
error(t.getMessage());
} else {//其他错误
error(t.getMessage());
}
}
}
使用
ApiClient.getInstance().getService().getWxArticle().enqueue(new CallBack2<List<WxArticle>>() {
@Override
public void success(List<WxArticle> wxArticles) {
//显示数据
}
@Override
public void failure(int code,String msg) {
//提示服务器错误
}
@Override
public void error(String msg) {
//其他错误
}
});
当时我就考虑到showLoadingDialog 得多处 dismissLoadingDialog,抽象的方法太多了 额外的增加很多其他代码,所以增加一个对象来保存错误。
showLoadingDialog();
ApiClient.getInstance().getService().getWxArticle().enqueue(new CallBack2<List<WxArticle>>() {
@Override
public void success(List<WxArticle> wxArticles) {
dismissLoadingDialog();
//显示数据
}
@Override
public void failure(int code, String msg) {
dismissLoadingDialog();
//提示服务器错误
}
@Override
public void error(String msg) {
dismissLoadingDialog();
//其他错误
}
});
再次改进
// 访问服务器成功直接获取数据
public abstract void success(T t);
// 服务器错误返回code 和message 和其他错误
public abstract void failure(ApiErrorModel apiErrorModel);
四、统一错误提示
public final class ApiErrorModel {
public static final int SERVER_ERROR = 0;
public static final int OTHER_ERROR = 1;
private int errorType;
private int errorCode;
private String errorMsg;
public ApiErrorModel(int errorType, String errorMsg) {
this.errorType = errorType;
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public ApiErrorModel(int httpCode, int errorCode, String errorMsg) {
this.errorType = errorType;
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public boolean isOtherError() {
return getErrorType() == OTHER_ERROR;
}
public int getErrorType() {
return errorType;
}
public int getErrorCode() {
return errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
}
public abstract class CallBack<T> implements Callback<BaseCallModel<T>> {
public static final int SUCCESS_CODE = 0;
public abstract void success(T t);
public abstract void failure(ApiErrorModel apiErrorModel);
@Override
public void onResponse(Call<BaseCallModel<T>> call, Response<BaseCallModel<T>> response) {
if (response.isSuccessful() && response.body() != null) {
if (response.body().getErrorCode() == SUCCESS_CODE) {
success(response.body().getData());
} else {
failure(new ApiErrorModel(ApiErrorModel.SERVER_ERROR, response.body().getErrorCode(), response.body().getErrorMsg()));
}
}
}
@Override
public void onFailure(Call<BaseCallModel<T>> call, Throwable t) {
ApiErrorModel apiErrorModel;
if (t instanceof SocketTimeoutException) {//超时
apiErrorModel = new ApiErrorModel(ApiErrorModel.SERVER_ERROR, "超时");
} else if (t instanceof ConnectException) {//连接错误
apiErrorModel = new ApiErrorModel(ApiErrorModel.SERVER_ERROR, "连接错误");
} else if (t instanceof UnknownError) { //未找到主机
apiErrorModel = new ApiErrorModel(ApiErrorModel.SERVER_ERROR, "未找到主机");
} else {//其他错误
apiErrorModel = new ApiErrorModel(ApiErrorModel.SERVER_ERROR, "未知错误");
}
failure(apiErrorModel);
}
}
使用
ApiClient.getInstance().getService().getWxArticle().enqueue(new CallBack<List<WxArticle>>() {
@Override
public void success(List<WxArticle> wxArticles) {
//显示数据
}
@Override
public void failure(ApiErrorModel apiErrorModel) {
// 提示
Toast.makeText(CallBackTestActivity.this, apiErrorModel.getErrorMsg(), Toast.LENGTH_SHORT).show();
}
});
带Code处理
ApiClient.getInstance().getService().getWxArticle().enqueue(new CallBack<List<WxArticle>>() {
@Override
public void success(List<WxArticle> wxArticles) {
//显示数据
}
@Override
public void failure(ApiErrorModel apiErrorModel) {
if (apiErrorModel.isOtherError()) {
// 提示
Toast.makeText(CallBackTestActivity.this, apiErrorModel.getErrorMsg(), Toast.LENGTH_SHORT).show();
return;
}
// 处理业务
int code = apiErrorModel.getErrorCode();
......
}
});
五、模糊化错误提示
我以为就这样完事的时候,告诉我需要模糊化错误提示,不能明确的告诉用户准确的错误。好吧!继续改进
1.通过枚举类管理所以的用户提示错误。
public enum ApiErrorType {
NETWORK_NOT_CONNECT(1, R.string.network_not_connection), // 请检查网络连接
NETWORK_ERROR(2, R.string.network_error), // 网络异常,请稍后再试!
SERVER_ERROR(3, R.string.server_error), // 服务器发生错误
UNKNOWN_ERROR(4, R.string.unknown_error); // 未知错误
private final int code;
private final int messageId;
public int getMessageId() {
return messageId;
}
ApiErrorType(int code, @StringRes int messageId) {
this.code = code;
this.messageId = messageId;
}
public ApiErrorModel getApiErrorModel() {
Context context = App.getInstance().getApplicationContext();
return new ApiErrorModel(ApiErrorModel.OTHER_ERROR, code, context.getString(messageId));
}
}
2.发生错误时模糊化提示
public abstract class CompleteCallBack<T> implements Callback<BaseCallModel<T>> {
public static final int SUCCESS_CODE = 0;
public abstract void success(T t);
public abstract void failure(ApiErrorModel apiErrorModel);
@Override
public void onResponse(Call<BaseCallModel<T>> call, Response<BaseCallModel<T>> response) {
if (response.isSuccessful() && response.body() != null) {
if (response.body().getErrorCode() == SUCCESS_CODE) {
success(response.body().getData());
} else {
failure(new ApiErrorModel(ApiErrorModel.SERVER_ERROR, response.body().getErrorCode(), response.body().getErrorMsg()));
}
}
}
@Override
public void onFailure(Call<BaseCallModel<T>> call, Throwable t) {
ApiErrorType apiErrorType;
if (t instanceof UnknownHostException) {
apiErrorType = ApiErrorType.SERVER_ERROR;
} else if (t instanceof ConnectException) {
apiErrorType = ApiErrorType.NETWORK_NOT_CONNECT;
} else if (t instanceof SocketTimeoutException) {
apiErrorType = ApiErrorType.NETWORK_ERROR;
} else {
apiErrorType = ApiErrorType.UNKNOWN_ERROR;
}
failure(apiErrorType.getApiErrorModel());
}
}
3.具体使用--依旧没变
提示
ApiClient.getInstance().getService().getWxArticle().enqueue(new CompleteCallBack<List<WxArticle>>() {
@Override
public void success(List<WxArticle> wxArticles) {
}
@Override
public void failure(ApiErrorModel apiErrorModel) {
Toast.makeText(MainActivity.this, apiErrorModel.getErrorMsg(), Toast.LENGTH_SHORT).show();
}
});
带code
ApiClient.getInstance().getService().getWxArticle().enqueue(new CompleteCallBack<List<WxArticle>>() {
@Override
public void success(List<WxArticle> wxArticles) {
}
@Override
public void failure(ApiErrorModel apiErrorModel) {
if (apiErrorModel.isOtherError()) {
// 提示
Toast.makeText(MainActivity.this, apiErrorModel.getErrorMsg(), Toast.LENGTH_SHORT).show();
return;
}
// 处理业务
int code = apiErrorModel.getErrorCode();
......
}
});
总结
简单的封装一下CallBack,分离了CallBack中业务处理。在success只关注获取数据,failure处理网络连接中的异常。
由于本人水平有限,如果有错误和需要改进的地方,还希望大家多多指教,共同进步。
GitHub: