<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
不知道你們在使用Retrofit存取後臺介面時返回的資料是否是一樣的格式,比如登入介面,在我們輸入密碼成功或錯誤的時候後臺返回的資料格式是不同的,這樣我們在新增GsonConverterFactory
解析後臺資料時由於後臺會返回兩種不同的資料所以會導致Gson
解析失敗的錯誤資訊。這裡以自己專案的登入介面為例子記錄下自己的解決方案。
登入成功和失敗的兩種資料格式:
{"success":false,"code":-1,"msg":"密碼錯誤","data":"密碼錯誤"}
{"success":true,"code":1,"msg":"操作成功","data":{"JXHDAPIToken":"1ccf7b01ed544882aacda365c8f620d2"}}
從上面資料中我們可以發現後臺返回的資料只有data中的資料是不一樣,其他幾個欄位都是一樣的。這個時候我們可以將幾個相同欄位抽取出來,通過修改GsonConverterFactory
來實現解析不同資料。
修改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
中檢視它的程式碼結構:
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
的情況下我們正常返回資料即可,為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
的情況下返回的資料:
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
原始碼內容是一樣的,我們直接將內容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())
這個時候我們再去呼叫之前的登入介面,當我們登入失敗的時候會進入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) { //這裡面根據自己專案需求進行操作,比如code判斷。 if (t instanceof DataResultException) { DataResultException resultException = (DataResultException) t; Log.d(TAG, "Code: " + resultException.getCode() + "Message:" + resultException.getMessage()); } }
封裝後我們只會呼叫onNext
的方法,當然我們如果需要其他操作的話也可以將其他幾個方法重寫:
RetrofitUtils.getInstance().getApi().login() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new MySubscriber<LoginResult>() { @Override public void onNext(LoginResult loginResult) { //登入成功 } });
好了,到這裡就結束了,不知不覺感覺時間過的好快,總感覺自己的時間不夠用,感覺還有好多好多東西需要自己去學習但總是莫名的懶惰。哈哈,希望自己在以後的道路上能繼續努力慢慢成長。
到此這篇關於Android使用Retrofit實現自定義Converter解析介面流程詳解的文章就介紹到這了,更多相關Android自定義Converter解析介面內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45