上兩篇文章主要講述尋找問題根源到解決思路,解決辦法比較複雜,這裏提供一種最簡單的解決辦法,不需要改動太多的東西:
比如一般後臺返回的數據格式如下:
正常數據
{"code":200,"data":{"id":"adsd","name":"Weipru"},"msg":"success","timeStamp":"20191015102953"}
不存在data的數據
{"code":1000,"data":"","msg":"請登錄!","timeStamp":"20191014094718"}
對應我們自己的Http響應實體
public class HttpMessage<T> {
private int code;
private T data;
private String msg;
private String timeStamp;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getTimeStamp() {
return timeStamp;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public void setTimeStamp(String timeStamp) {
this.timeStamp = timeStamp;
}
}
正常訪問後臺流程
- 後臺API
public interface GsonTestAPI {
@GET("/user/list")
Call<HttpMessage<List<UserAuthen>>> getUserList();
@GET("/user/info")
Call<HttpMessage<UserInfo>> getUserInfo();
}
- 調用API,獲取數據
messageCall.enqueue(new Callback<HttpMessage<UserInfo>>() {
@Override
public void onResponse(Call<HttpMessage<UserInfo>> call, Response<HttpMessage<UserInfo>> response) {
Log.i(TAG, "onResponse: " + response.body().getCode());
}
@Override
public void onFailure(Call<HttpMessage<UserInfo>> call, Throwable t) {
Log.i(TAG, "onResponse: " + t.getMessage());
t.printStackTrace();
}
});
同理,data類型爲泛型數組時:
Call<HttpMessage<List<UserAuthen>>> messageCall = userServiceAPI.getUserList();
messageCall.enqueue(new Callback<HttpMessage<List<UserAuthen>>>() {
@Override
public void onResponse(Call<HttpMessage<List<UserAuthen>>> call, Response<HttpMessage<List<UserAuthen>>> response) {
Log.i(TAG, "onResponse: " + response.body().getCode());
}
@Override
public void onFailure(Call<HttpMessage<List<UserAuthen>>> call, Throwable t) {
Log.i(TAG, "onResponse: " + t.getMessage());
t.printStackTrace();
}
});
如果返回正常數據,則可以正確解析並返回,否正直接拋出異常,怎麼解決呢?
同樣也需要自定義一個自己的轉換器,需要三個類:
-
GsonConverFactory
- GsonResponseBodyConverter
- GsonRequestBodyConverter
直接從源碼中複製出來 換成自己的名字即可,,現在只處理響應體轉換器GsonResponseBodyConverter,代碼如下:
- 在GsonConverFactory中返回自己的轉換器,至展示關鍵部分
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
Log.w("TYPE", "類型是 " + type.getTypeName());//
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new WGsonResponseBodyConverter<>(gson, adapter);
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new WGsonRequestBodyConverter<>(gson, adapter);
}
- 在WGsonResponseBodyConverter中做狀態判斷:
public T convert(ResponseBody value) throws IOException {
try {
//因爲value只能被讀取一次,所以這裏必須把讀取結果存起來,給下次使用
String reponseString = value.string();
HttpMessage httpMessage = gson.fromJson(reponseString, HttpMessage.class);
if (httpMessage.getCode() != 200) {
return (T) httpMessage;//直接返回,data字段不做類型轉換
}
MediaType contentType = value.contentType();
Charset charset = contentType != null ? contentType.charset(UTF_8) : UTF_8;
InputStream inputStream = new ByteArrayInputStream(reponseString.getBytes());
Reader reader = new InputStreamReader(inputStream, charset);
JsonReader jsonReader = gson.newJsonReader(reader);
return adapter.read(jsonReader);
} finally {
value.close();
}
}
使用自定義的轉換器即可:
userServiceAPI = new Retrofit.Builder()
.client(builder.build())
.baseUrl(this.host).addConverterFactory(WGsonConverFactory.create())//使用自己的轉換器
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
.create(GsonTestAPI.class);