retrofit 对callback错误的统一处理

前言

在使用 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 的学习和整理。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • 整体Retrofit内容如下: 1、Retrofit解析1之前哨站——理解RESTful 2、Retrofit解析...
    隔壁老李头阅读 3,114评论 5 14
  • 前言RxJava和Retrofit也火了一段时间了,不过最近一直在学习ReactNative和Node相关的姿势,...
    AFinalStone阅读 536评论 0 0
  • 开始使用Retrofit 首先先声明一个用于请求的接口 Converter.Factory factory = G...
    zyc_214阅读 349评论 0 0
  • 适配器模式上一篇文章我们已经分析了Retrofit解析注解封装进ServiceMethod的流程,读者在这里要记住...
    andcoder阅读 643评论 0 2