Android使用Retrofit實現(xiàn)自定義Converter解析接口流程詳解
不知道你們在使用Retrofit訪問后臺接口時返回的數(shù)據(jù)是否是一樣的格式,比如登錄接口,在我們輸入密碼成功或錯誤的時候后臺返回的數(shù)據(jù)格式是不同的,這樣我們在添加GsonConverterFactory解析后臺數(shù)據(jù)時由于后臺會返回兩種不同的數(shù)據(jù)所以會導致Gson解析失敗的錯誤信息。這里以自己項目的登錄接口為例子記錄下自己的解決方案。
登錄成功和失敗的兩種數(shù)據(jù)格式:
{"success":false,"code":-1,"msg":"密碼錯誤","data":"密碼錯誤"}{"success":true,"code":1,"msg":"操作成功","data":{"JXHDAPIToken":"1ccf7b01ed544882aacda365c8f620d2"}}從上面數(shù)據(jù)中我們可以發(fā)現(xiàn)后臺返回的數(shù)據(jù)只有data中的數(shù)據(jù)是不一樣,其他幾個字段都是一樣的。這個時候我們可以將幾個相同字段抽取出來,通過修改GsonConverterFactory來實現(xiàn)解析不同數(shù)據(jù)。
修改GsonConverterFactory:
我們只需要點擊進入GsonConverterFactory的源碼中看看它的代碼,這里面我們只需要修改返回的GsonResponseBodyConverter對象。
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);所以我們再點擊進入GsonResponseBodyConverter中查看它的代碼結(jié)構(gòu):
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter<T> adapter;
GsonResponseBodyConverter(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());
try {
return adapter.read(jsonReader);
} finally {
value.close();
}
}
}我們是無法直接在GsonResponseBodyConverter里面直接進行修改的,所以我們可以自定義一個MyGsonResponseBodyConverter類:
final class MyGsonResponseBodyConverter<T> implements Converter<ResponseBody,T>{
private Gson gson;
private Type type;
public MyGsonResponseBodyConverter(Gson gson, Type type) {
this.gson = gson;
this.type = type;
}
@Override
public T convert(ResponseBody value) throws IOException {
String response = value.string();
try {
BaseBean baseBean = gson.fromJson(response,BaseBean.class);
if (!baseBean.isSuccess()) {
throw new DataResultException(baseBean.getMsg(),baseBean.getCode());
}
return gson.fromJson(JsonUtils.getData(response),type);
}finally {
value.close();
}
}
}這里面我們通過自己抽取出來的BaseBean去判斷當前接口返回的字段success,如果為true的情況下我們正常返回數(shù)據(jù)即可,為false的情況我們通過自定義DataResultException異常類將其拋出。
public class BaseBean {
private boolean success;
private int code;
private String msg;
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
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;
}
}通過DataResultException獲取success為false的情況下返回的數(shù)據(jù):
public class DataResultException extends IOException {
private String msg;
private int code;
public DataResultException(String msg, int code) {
this.msg = msg;
this.code = code;
}
public DataResultException(String message, String msg, int code) {
super(message);
this.msg = msg;
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}這個時候我們對GsonConverterFactory的修改就基本完成了,但是我們要使用它的時候還需要在自定義MyGsonConverterFactory和MyGsonRequestBodyConverter兩個類。
public 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());
}這里主要是為了將之前自定義的MyGsonResponseBodyConverter添加進去,而MyGsonRequestBodyConverter這個類和GsonRequestBodyConverter源碼內(nèi)容是一樣的,我們直接將內(nèi)容copy過來即可。
public final class MyGsonConverterFactory extends Converter.Factory {
public static MyGsonConverterFactory create() {
return create(new Gson());
}
public static MyGsonConverterFactory create(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
return new MyGsonConverterFactory(gson);
}
private final Gson gson;
private MyGsonConverterFactory(Gson gson) {
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);
}
}我們只需要將MyGsonConverterFactory替換之前的GsonConverterFactory即可:addConverterFactory(MyGsonConverterFactory.create())
這個時候我們再去調(diào)用之前的登錄接口,當我們登錄失敗的時候會進入onError方法中,這個時候我們就可以判斷是否拋出的是我們自定義的異常,如果是的話,那我們就可以獲得當前的msg和code值從而去進行一些操作:
RetrofitUtils.getInstance().getApi().login()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<LoginResult>() {
@Override
public void onSubscribe(Subscription s) {
}
@Override
public void onNext(LoginResult loginResult) {
}
@Override
public void onError(Throwable t) {
if (t instanceof DataResultException) {
DataResultException resultException = (DataResultException) t;
Log.d(TAG, "Code: " + resultException.getCode() + "Message:" + resultException.getMessage());
}
}
@Override
public void onComplete() {
}
});這里我們可以對Subscriber進行一下封裝,要不我們每次請求都需要去進行判斷顯得很是繁瑣:
public abstract class MySubscriber<T> implements Subscriber<T> {
@Override
public void onSubscribe(Subscription s) {
s.request(Long.MAX_VALUE);
}
@Override
public void onComplete() {
}
@Override
public void onError(Throwable t) {
//這里面根據(jù)自己項目需求進行操作,比如code判斷。
if (t instanceof DataResultException) {
DataResultException resultException = (DataResultException) t;
Log.d(TAG, "Code: " + resultException.getCode() + "Message:" + resultException.getMessage());
}
}封裝后我們只會調(diào)用onNext的方法,當然我們?nèi)绻枰渌僮鞯脑捯部梢詫⑵渌麕讉€方法重寫:
RetrofitUtils.getInstance().getApi().login()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new MySubscriber<LoginResult>() {
@Override
public void onNext(LoginResult loginResult) {
//登錄成功
}
});好了,到這里就結(jié)束了,不知不覺感覺時間過的好快,總感覺自己的時間不夠用,感覺還有好多好多東西需要自己去學習但總是莫名的懶惰。哈哈,希望自己在以后的道路上能繼續(xù)努力慢慢成長。
到此這篇關(guān)于Android使用Retrofit實現(xiàn)自定義Converter解析接口流程詳解的文章就介紹到這了,更多相關(guān)Android自定義Converter解析接口內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android高級組件ImageSwitcher圖像切換器使用方法詳解
這篇文章主要為大家詳細介紹了Android高級組件ImageSwitcher圖像切換器的使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-12-12
Android 彈出Dialog時隱藏狀態(tài)欄和底部導航欄的方法
這篇文章主要介紹了Android 彈出Dialog時隱藏狀態(tài)欄和底部導航欄的實例代碼,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-07-07
如何通過Android Logcat插件分析firebase崩潰問題
android crash Crash(應用崩潰)是由于代碼異常而導致App非正常退出,導致應用程序無法繼續(xù)使用,所有工作都停止的現(xiàn)象,本文重點介紹如何通過Android Logcat插件分析firebase崩潰問題,感興趣的朋友一起看看吧2024-01-01
Android消息通知Notification常用方法(發(fā)送消息和接收消息)
最近在做消息通知類Notification的相關(guān)業(yè)務,利用閑暇時間總結(jié)一下,主要分為兩部分來記錄:發(fā)送消息和接收消息,對Android消息通知相關(guān)知識感興趣的朋友一起看看吧2024-02-02
Android波紋擴散效果之仿支付寶咻一咻功能實現(xiàn)波紋擴散特效
這篇文章主要介紹了Android波紋擴散效果之仿支付寶咻一咻功能實現(xiàn)波紋擴散特效的相關(guān)資料,需要的朋友可以參考下2016-02-02
Android 6.0上sdcard和U盤路徑獲取和區(qū)分方法
今天小編就為大家分享一篇Android 6.0上sdcard和U盤路徑獲取和區(qū)分方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08
丟失Android系統(tǒng)庫或者Conversion to Dalvik format failed with error
這篇文章主要介紹了丟失Android系統(tǒng)庫或者Conversion to Dalvik format failed with error 1錯誤的解決方法,分析了Android系統(tǒng)庫丟失及版本問題的處理技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-12-12
Android使用第三方服務器Bmob實現(xiàn)發(fā)送短信驗證碼
這篇文章主要介紹了Android使用第三方服務器Bmob實現(xiàn)發(fā)送短信驗證碼的思路詳解,需要的朋友可以參考下2016-09-09
Android控件Chronometer定時器的實現(xiàn)方法
這篇文章主要為大家詳細介紹了Android控件Chronometer定時器的實現(xiàn)方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-11-11

