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