关于Retrofit返回错误信息的统一解决办法

最近哥们儿遇到的一个棘手难题,关于Retrofit请求的处理,一开始我觉得这种一般简单,根据返回code来就行,框架都给封装好了啊,之后自己上手之后才发现有些还是需要处理的。

问题如下图所示:

我来解释一下,Call里面的泛型和返回的对应不上,但是还是会走成功,同时response.isSuccess()为tue,对象里面的属性全是null(很好理解,因为JavaBean根本对应不上啊),奇怪的是Gson并没有抛错,郁闷,所以我们就只能手动处理这些异常了!
首先特别感谢博主的文章Retrofit统一处理服务器返回参数,这篇文章已经非常完整详细地讲解了Retrofit的相关处理办法,只是苦于木有Demo,我这边自己写Demo的时候还遇到了一个坑,就是没有办法收到异常,最终发现原来是Exception继承的问题,我一开始继承了Exception,后来才发现RunTimeException才可以中断之后的操作,所以修改如下。

package com.marsjiang.myretrofiterrortest.expection;

/**
 * Created by Jiang on 2017-09-28.
 */

public class MyException extends RuntimeException  {
    public MyException(){
        super();
    }
    public MyException(String msg){
        super(msg);
    }
}
返回消息类和原博主保持一致:

package com.marsjiang.myretrofiterrortest.bean;

/**
 * Created by Jiang on 2017-09-28.
 */

public class Result<T> {
    private int state;
    private String msg;
    private T data;

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}


下面来介绍其他的主要类(具体的讲解大家可以参考上篇博主的文章,写的非常棒,我就不啰嗦了):

MyGsonConverterFactory

package com.marsjiang.myretrofiterrortest.myretrofit;

import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;

/**
 * Created by Jiang on 2017-09-28.
 */

public final class MyGsonConverterFactory extends Converter.Factory {
    /**
     * Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
     * decoding from JSON (when no charset is specified by a header) will use UTF-8.
     */
    public static MyGsonConverterFactory create() {
        return create(new Gson());
    }

    /**
     * Create an instance using {@code gson} for conversion. Encoding to JSON and
     * decoding from JSON (when no charset is specified by a header) will use UTF-8.
     */
    public static MyGsonConverterFactory create(Gson gson) {
        return new MyGsonConverterFactory(gson);
    }

    private final Gson gson;

    private MyGsonConverterFactory(Gson gson) {
        if (gson == null) throw new NullPointerException("gson == null");
        this.gson = gson;
    }

    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
                                                            Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new MyGsonResponseBodyConverter<>(gson, adapter);
    }

    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type,
                                                          Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return (Converter<?, RequestBody>) new MyGsonResponseBodyConverter<>(gson, adapter);
    }
}

MyGsonResponseBodyConverter:

package com.marsjiang.myretrofiterrortest.myretrofit;

import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.marsjiang.myretrofiterrortest.bean.Result;
import com.marsjiang.myretrofiterrortest.expection.MyException;

import java.io.IOException;
import java.io.StringReader;

import okhttp3.ResponseBody;
import retrofit2.Converter;

/**
 * Created by Jiang on 2017-09-28.
 */

final class MyGsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
    private final Gson gson;
    private final TypeAdapter<T> adapter;

    private static final int FAILURE = 0;       // 失败 提示失败msg
    private static final int SUCCESS = 1;       // 成功
    private static final int TOKEN_EXPIRE = 2;  // token过期
    private static final int SERVER_EXCEPTION = 3;  // 服务器异常

    MyGsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
        this.gson = gson;
        this.adapter = adapter;
    }

    @Override
    public T convert(ResponseBody value) throws IOException {
        JsonReader jsonReader = gson.newJsonReader(value.charStream());
        String json = value.string();
        try {
            verify(json);
//            return adapter.read(jsonReader);
            return adapter.read(gson.newJsonReader(new StringReader(json)));
        } finally {
            value.close();
        }
    }

    private void verify(String json) {
        Result result = gson.fromJson(json, Result.class);
        if (result.getState() != SUCCESS) {
            int a = result.getState();
            switch (result.getState()) {
                case SERVER_EXCEPTION:
                    throw new MyException(result.getMsg());
                case TOKEN_EXPIRE:
                    throw new MyException(result.getMsg());
                default:
//                    throw new MyException("不清楚什么原因!");
            }
        }
    }

}

这样抛出来的异常就可以被retrofit的onFailure()方法接收到了!关于异常的code大家自己去和服务端定好就行! 微笑


在MainActivity中,我添加了一个okhttp过滤器,旨在监听每个请求,并将其打印出来,前提是大家需要导入一个第三方:


compile 'com.squareup.okhttp3:logging-interceptor:3.1.2'

下面是完整代码:

package com.marsjiang.myretrofiterrortest;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import com.marsjiang.myretrofiterrortest.bean.Result;
import com.marsjiang.myretrofiterrortest.bean.UserReturnBean;
import com.marsjiang.myretrofiterrortest.myretrofit.MyGsonConverterFactory;

import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;

public class MainActivity extends AppCompatActivity {
    private Retrofit retrofit;
    private String ipPortString;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ipPortString = "192.168.10。19:8080";
        String url = "http://" + ipPortString + "/XiaoXiao/";
        retrofit = new Retrofit.Builder()
                .baseUrl(url)
                .addConverterFactory(MyGsonConverterFactory.create())
                .client(getOkHttpClient())
                .build();

        ApiCore userBiz = retrofit.create(ApiCore.class);
        Call<Result<UserReturnBean>> call = userBiz.getLoginInfo();
        call.enqueue(new Callback<Result<UserReturnBean>>() {
            @Override
            public void onResponse(Call<Result<UserReturnBean>> call, Response<Result<UserReturnBean>> response) {
                if (response.isSuccessful()) {
                    if (response.body().getData() == null) {

                    }
                    Log.e("infoooo", "normalGet:" + response.body() + "");
                }
            }

            @Override
            public void onFailure(Call<Result<UserReturnBean>> call, Throwable t) {
                Log.e("infoooo", "normalGet:" + t.toString() + "");
            }
        });

    }

    /**
     * 获取okhttp拦截器
     *
     * @return
     */
    public OkHttpClient getOkHttpClient() {
        //日志显示级别
        HttpLoggingInterceptor.Level level = HttpLoggingInterceptor.Level.BODY;
        //新建log拦截器
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
            @Override
            public void log(String message) {
                Log.d("zcb", "OkHttp====Message:" + message);
            }
        });
        loggingInterceptor.setLevel(level);
        //定制OkHttp
        OkHttpClient.Builder httpClientBuilder = new OkHttpClient
                .Builder();
        //OkHttp进行添加拦截器loggingInterceptor
        httpClientBuilder.addInterceptor(loggingInterceptor);
        return httpClientBuilder.build();
    }
}

嗯,这样每次就能打印出来了!

代码是最好的老师!

gitHub地址:

点击打开链接



还是那句话,做好自己,加油!

猜你喜欢

转载自blog.csdn.net/u010724819/article/details/78123397