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

时间:2020-11-29 18:03:28

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

问题如下图所示:

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

我来解释一下,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大家自己去和服务端定好就行! 关于Retrofit返回错误信息的统一解决办法


在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地址:

点击打开链接


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

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