retrofit2使用详解_秒懂Retrofit2之Converter
>【版權(quán)申明】非商業(yè)目的注明出處可自由轉(zhuǎn)載
博文地址:https://blog.csdn.net/ShuSheng0007/article/details/89675797
出自:shusheng007
系列文章
秒懂的Retrofit2源碼詳解?blog.csdn.net用Retrofit+RxJava2封裝優(yōu)雅的網(wǎng)絡(luò)請求框架?blog.csdn.net秒懂Retrofit2之GsonConverter?blog.csdn.net@[toc]
概述
Retrofit2 已經(jīng)成為Android開發(fā)中網(wǎng)絡(luò)請求方面當(dāng)之無愧的扛把子了,我們很有必要對自己經(jīng)常使用的東西有個(gè)較為深入的理解。
Retrofit2 中有兩個(gè)非常精彩的設(shè)計(jì):Converter 與CallAdapter, 通過這兩個(gè)接口,Retrofit2的可擴(kuò)展性被極大的增強(qiáng)了,用戶可以根據(jù)需求自由擴(kuò)展。我們這篇文章就對Converter做一個(gè)比較深入的解析。
作用
例如我們有如下代碼片段:其中User 和 Person 是兩個(gè)自定義類
@POSTObservable<List<User>>method1(@Body Person rBody);那么retrofit2是怎么認(rèn)識(shí)我們自定義的類呢?這就是Converter 要干的事情。
下面是 Converter接口的源代碼:
//將F類型的值轉(zhuǎn)化為T類型的值 public interface Converter<F, T> {T convert(F value) throws IOException;abstract class Factory {//將API方法的返回類型從ResponseBody 轉(zhuǎn)換為type,type是由CallAdapter 接口里面的responseType()函數(shù)返回的。public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type,Annotation[] annotations, Retrofit retrofit) {return null;}//將API方法的輸入?yún)?shù)類型從 type轉(zhuǎn)換為ResponseBody , 用于轉(zhuǎn)換被注解@Body, @Part 和 @PartMap標(biāo)記的類型public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {return null;}//將API方法的輸入?yún)?shù)類型從 type 轉(zhuǎn)換為String,用于轉(zhuǎn)換被注解 @Header, @HeaderMap, @Path, @Query 和 @QueryMap 標(biāo)記的類型public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,Retrofit retrofit) {return null;}//下面是兩個(gè)工具方法protected static Type getParameterUpperBound(int index, ParameterizedType type) {return Utils.getParameterUpperBound(index, type);}protected static Class<?> getRawType(Type type) {return Utils.getRawType(type);}} }通過其源碼可見其只有一個(gè)方法 T convert(F value),就是將F類型的value轉(zhuǎn)換為T類型的輸出值。不同的Converter可以通過其內(nèi)部類Factory得到。
使用原理
那么converter是如果作用于retrofit2的呢? 我們可以在retrofit2的源碼中搜索 T convert(F value)的引用,如下圖所示.我們可以發(fā)現(xiàn) Converter的使用只有兩種場景:
第一:紅框中,使用Converter 將我們使用okhttp3 這個(gè)庫發(fā)起HTTP請求的返回值的類型(RequestBody)轉(zhuǎn)換為我們自定義的類型(T)。 針對我們上面的示例代碼為:將RequestBody類型轉(zhuǎn)換為List<User>類型
第二:藍(lán)框中,使用Converter 將我們的輸入?yún)?shù)類型從自定義類型轉(zhuǎn)換為RequestBody 或者String。 針對我們上面的示例代碼為:將Person類型轉(zhuǎn)換為RequestBody 類型
因?yàn)閞etrofit2在代碼中是針對Converter 這個(gè)接口編程的,所以我們就可以為這個(gè)接口提供很多種具體的實(shí)現(xiàn)。Retrofits2中有一個(gè)默認(rèn)的實(shí)現(xiàn)BuiltInConverters,讓我們來看一下:
final class BuiltInConverters extends Converter.Factory {//做的工作很簡單,這里要求方法返回值類型type必須為ResponseBody或者Void,轉(zhuǎn)化后的類型為ResponseBody。//返回相應(yīng)的Converter實(shí)例,其他的類型都處理不了,直接返回null//當(dāng)方法返回值類型type是ResponseBody時(shí)檢查一下方法是否使用了@Streaming注解標(biāo)識(shí),如果沒有標(biāo)識(shí)則將數(shù)據(jù)全部讀取到內(nèi)存中,返回一個(gè)ResponseBody@Overridepublic Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {if (type == ResponseBody.class) {return Utils.isAnnotationPresent(annotations, Streaming.class)? StreamingResponseBodyConverter.INSTANCE: BufferingResponseBodyConverter.INSTANCE;}if (type == Void.class) {return VoidResponseBodyConverter.INSTANCE;}return null;}//更簡單,要求方法的請求參數(shù)type必須為RequestBody類型,得到的類型也是RequestBody,沒有做任何類型轉(zhuǎn)換,//返回相應(yīng)的Converter實(shí)例,其他的類型都處理不了,直接返回null@Overridepublic Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {if (RequestBody.class.isAssignableFrom(Utils.getRawType(type))) {return RequestBodyConverter.INSTANCE;}return null;}//將object轉(zhuǎn)成Stringstatic final class ToStringConverter implements Converter<Object, String> {static final ToStringConverter INSTANCE = new ToStringConverter();@Override public String convert(Object value) {return value.toString();}}...static final class VoidResponseBodyConverter implements Converter<ResponseBody, Void> {static final VoidResponseBodyConverter INSTANCE = new VoidResponseBodyConverter();@Override public Void convert(ResponseBody value) {value.close();return null;}}static final class RequestBodyConverter implements Converter<RequestBody, RequestBody> {static final RequestBodyConverter INSTANCE = new RequestBodyConverter();@Override public RequestBody convert(RequestBody value) {return value;}}//如果使用Streaming注解標(biāo)記了方法,則使用這個(gè)轉(zhuǎn)換器直接返回responseBody類型的數(shù)據(jù),不讀取到內(nèi)存static final class StreamingResponseBodyConverterimplements Converter<ResponseBody, ResponseBody> {static final StreamingResponseBodyConverter INSTANCE = new StreamingResponseBodyConverter();@Override public ResponseBody convert(ResponseBody value) {return value;}}//如果不使用Streaming注解標(biāo)記方法,則將返回值讀取到內(nèi)存中static final class BufferingResponseBodyConverterimplements Converter<ResponseBody, ResponseBody> {static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter();@Override public ResponseBody convert(ResponseBody value) throws IOException {try {// Buffer the entire body to avoid future I/O.return Utils.buffer(value);} finally {value.close();}}} }上面代碼非常簡單,在其中關(guān)鍵的兩個(gè)方法上我也加了很詳細(xì)的注釋,沒有太多可以解釋的。其中值得注意的是那個(gè)stringConverter,由于沒有對入?yún)⒌囊蕾?#xff0c;所以沒有采用實(shí)現(xiàn)Converter.Factory里面的
public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,Retrofit retrofit) {return null;}這種方式來實(shí)現(xiàn)。
通過以上源碼我們可以解釋很多Retrofit2的行為,例如 1:如果不添加自定義Converter,我們在定義方法時(shí)方法的入?yún)⒌念愋椭荒苁荝equestBody或者String,而返回值的泛型參數(shù)類型也只能是RequestBody 或者Void的現(xiàn)象。 2:如果不使用@Stream 注解標(biāo)識(shí)方法,那么下載大文件時(shí)會(huì)發(fā)生OOM的問題,因?yàn)槠鋾?huì)將返回?cái)?shù)據(jù)一次性載入內(nèi)存中。
如果是僅僅使用默認(rèn)的Converter的話Retrofit2的使用將會(huì)受到極大的限制,但大神們是不允許這樣的事發(fā)生的,所以我們可以自由使用各種Converter來滿足我們的需求,再一次感受到了面向抽象編程的強(qiáng)大。
日常開發(fā)中最為常用的就是GsonConverter,但是現(xiàn)實(shí)中絕不僅僅只有GsonConverter,還有g(shù)uava、jackson、java8、jaxb、moshi、protobuf、scalars、simplexml、wire 等Converter,如果別人寫好的Converter不能滿足我們的需求,那我們就需要自己寫一個(gè)。
關(guān)于GsonConverter 請查看秒懂Retrofit2之GsonConverter
總結(jié)
可見一個(gè)設(shè)計(jì)優(yōu)良的類庫,會(huì)給用戶很大的擴(kuò)展空間,這一點(diǎn)我們應(yīng)該多加學(xué)習(xí)。
下一篇講下CallAdapter
總結(jié)
以上是生活随笔為你收集整理的retrofit2使用详解_秒懂Retrofit2之Converter的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: cat查看tomcat日志 linux_
- 下一篇: springboot 建readme_经