正常情況下我們開發(fā)app服務(wù)器返回的json一般是這樣標(biāo)準(zhǔn)的形式辖源。
{
"status": 1,
"msg": "message",
"data":{}
}
所以我們可以在客戶端定義這樣的格式來進(jìn)行統(tǒng)一處理肠阱。
public class Result<T> {
public int status;
public String msg;
public T data;
}
最近遇到了這樣的問題落蝙,服務(wù)器返回的data有時候是對象,有時候又是數(shù)組算墨,還有可能是字符串绍坝,這樣使用第三方解析就比較麻煩了徘意。但是需要處理返回code不為0的情況,比如給用戶一些提示什么的轩褐。所以寫下來作為記錄椎咧,防止以后再遇到。遇到這種坑,要么和后臺協(xié)商返回統(tǒng)一格式的json字符串勤讽,如果后臺不改蟋座,我們只能自己解決了。
一脚牍、使用自定義ConvertAdapter
Retrofit可以使用自定義的Converter向臀,它的作用是可以將接受到的json轉(zhuǎn)換成實體返回給我們。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ApiService.API_BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create()) // 就是這里
.addCallAdapterFactory(RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io()))
.build();
一般情況下我們都使用GsonConverterFactory诸狭,當(dāng)請求到j(luò)son后券膀,Retrofit就會調(diào)用GsonConverter將json轉(zhuǎn)成我們需要的實體。
GsonConverterFactory一共只有三個類驯遇,并且代碼量很少芹彬,如下:
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) {
return new MyGsonResponseBodyConverter<>(gson, type);
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new MyGsonRequestBodyConverter<>(gson, adapter);
}
}
final class MyGsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
private static final Charset UTF_8 = Charset.forName("UTF-8");
private final Gson gson;
private final TypeAdapter<T> adapter;
MyGsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override
public RequestBody convert(T value) throws IOException {
Buffer buffer = new Buffer();
Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
JsonWriter jsonWriter = gson.newJsonWriter(writer);
adapter.write(jsonWriter, value);
jsonWriter.close();
return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
}
}
主要操作在這個類進(jìn)行
public class MyGsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final Type type;
MyGsonResponseBodyConverter(Gson gson, Type type) {
this.gson = gson;
this.type = type;
apiHandle = new ApiHandle();
}
@Override
public T convert(ResponseBody value) throws IOException {
String response = value.string();
try {
return gson.fromJson(response, type);
} finally {
value.close();
}
}
當(dāng)我們發(fā)出一個POST JSON請求(直接用Retrofit post一個實體給服務(wù)器,請求的時候會自動將我們的實體轉(zhuǎn)成Json)的時候叉庐,Retrofit就會調(diào)用GsonRequestBodyConverter的Convert方法將我們的實體轉(zhuǎn)換成json舒帮。而接受服務(wù)器返回的數(shù)據(jù)時,Retrofit會調(diào)用GsonResponseBodyConverter將Json數(shù)據(jù)轉(zhuǎn)換成我們需要的實體陡叠。
既然如此玩郊,我們可以在Converter解析json的時候就做服務(wù)器參數(shù)的統(tǒng)一處理
我是將GsonConverterFactory的三個類拷貝出來修改了一下:GsonConverterFactory和RequestBodyConverter幾乎沒有任何修改,我們需要更改類是GsonResponseBodyConverter枉阵,因為它才是將服務(wù)器的數(shù)據(jù)轉(zhuǎn)換成實體了译红,我們在轉(zhuǎn)換的過程中做統(tǒng)一處理。
這里需要說明的是因為后臺返回的data時刻會改變岭妖,所以我們需要解決這個問題临庇,我是這么處理的,首先自己定義一個類去存放code和message
public class BaseBean {
private int code;
private String msg;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
這樣就能避免我們在解析data的時候出現(xiàn)解析錯誤昵慌,這里我的處理是在MyGsonResponseBodyConverter里面的convert方法攔截response
public T convert(ResponseBody value) throws IOException {
String response = value.string();
try {
BaseBean baseBean = gson.fromJson(response, BaseBean.class);//攔截code非0情況
if (baseBean.getCode() != 0) {
new Thread() {
@Override
public void run() {
Message msg = new Message();
msg.what = 1;
msg.obj = baseBean.getMsg();
handler.sendMessage(msg);
}
}.start();
}
return gson.fromJson(response, type);
} finally {
value.close();
}
}
這里我們判斷code非0就是請求沒有達(dá)到我們定義的預(yù)期效果假夺,我這里是簡單處理給了個吐司,也可以定義接口回調(diào)處理斋攀,但是因為是子線程所以要用handler更新ui已卷。
一般情況下如果data格式固定可以在這里自定義異常處理,因為我是data不固定淳蔼,只能先取cade和message簡單處理侧蘸。最好還是和后臺小哥協(xié)商好最好了。最好不要遇到這種坑~~~