国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

Android源碼進階之深入理解Retrofit工作原理

移動開發 Android
Retrofit是一個基于AOP思想,對RestfulApi注解進行動態代理的網絡框架;今天我們就來探討下實現原理,一起進步。

?[[422495]]??

本文轉載自微信公眾號「Android開發編程」,作者Android開發編程。轉載本文請聯系Android開發編程公眾號。

前言

Retrofit是一個基于AOP思想,對RestfulApi注解進行動態代理的網絡框架;

今天我們就來探討下實現原理,一起進步

一、使用Retrofit

1、包引用

在gradle文件中引用retrofit

compile 'com.squareup.retrofit2:retrofit:2.3.0'     compile 'com.squareup.retrofit2:retrofit-converters:2.3.0'     compile 'com.squareup.retrofit2:retrofit-adapters:2.3.0' 

如果需要使用更多擴展功能,比如gson轉換,rxjava適配等,可以視自己需要繼續添加引用;

compile 'com.squareup.retrofit2:converter-gson:2.3.0'     compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0' 

如果現有的擴展包不能滿足需要,還可以自己擴展converter,adapter等;

2、定義接口

Retrofit要求定義一個網絡請求的接口,接口函數里要定義url路徑、請求參數、返回類型;

public interface INetApiService {     @GET("/demobiz/api.php")     Call<BizEntity> getBizInfo(@Query("id") String id); } 

在這個接口定義中,用注解@GET("/demobiz/api.php")聲明了url路徑,用注解@Query("id") 聲明了請求參數;

最重要的是,用Call聲明了返回值是一個Retrofit的Call對象,并且聲明了這個對象處理的數據類型為BizEntity,BizEntity是我們自定義的數據模型;

3、依次獲得Retrofit對象、接口實例對象、網絡工作對象

首先,需要新建一個retrofit對象;

然后,根據上一步的接口,實現一個retrofit加工過的接口對象;

最后,調用接口函數,得到一個可以執行網絡訪問的網絡工作對象;

//新建一個Retrofit對象 Retrofit retrofit=new Retrofit.Builder() .baseUrl(Config.DOMAIN)//要訪問的網絡地址域名,如http://www.zhihu.com .addConverterFactory(GsonConverterFactory.create()) .build(); ... //用retrofit加工出對應的接口實例對象 INetApiService netApiService= retrofit.create(INetApiService.class); //可以繼續加工出其他接口實例對象 IOtherService otherService= retrofit.create(IOtherService.class); ··· //調用接口函數,獲得網絡工作對象 Call<BizEntity> callWorker= netApiService.getBizInfo("id001"); 

這個復雜的過程下來,最終得到的callWorker對象,才可以執行網絡訪問。

4、訪問網絡數據

用上一步獲取的worker對象,執行網絡請求

callWorker.enqueue(new Callback<BizEntity>() {             @Override             public void onResponse(Call<BizEntity> call, Response<BizEntity> response) {...}             @Override             public void onFailure(Call<BizEntity> call, Throwable t) {...}         }); 

在回調函數里,取得我們需要的BizEntity數據對象

二、Retrofit實現原理

???

1、Retrofit對象的構建就是簡單的builder模式,直接看create

//Retrofit.java public <T> T create(final Class<T> service) {     //驗證     validateServiceInterface(service);     return (T)         //動態代理         Proxy.newProxyInstance(         service.getClassLoader(), //類加載器         new Class<?>[] {service}, //一組接口         new InvocationHandler() {             //判斷android和jvm平臺及其版本             private final Platform platform = Platform.get();             @Override             public Object invoke(Object proxy, Method method, Object[] args){                 //如果該方法是Object的方法,直接執行不用管                 if (method.getDeclaringClass() == Object.class) {                     return method.invoke(this, args);                 }                 //isDefaultMethod:檢查是否是java8開始支持的接口默認方法                 return platform.isDefaultMethod(method)                     ? platform.invokeDefaultMethod(method, service, proxy, args)                     : loadServiceMethod(method).invoke(args); //我們關注這里             }         }); } 

Proxy.newProxyInstance動態代理,運行期會生成一個類(字節碼)如$ProxyN,實現傳入的接口即WanApi,重寫接口方法然后轉發給InvocationHandler的invoke

class $ProxyN extends Proxy implements WanApi{     Call<WanArticleBean> articleList(@Path("page") int page){         //轉發給invocationHandler         invocationHandler.invoke(this,method,args);     } } 

2、validateServiceInterface驗證邏輯

//Retrofit.java private void validateServiceInterface(Class<?> service) {     //檢查:WanApi不是接口就拋異常...     //檢查:WanApi不能有泛型參數,不能實現其他接口...     if (validateEagerly) { //是否進行嚴格檢查,默認關閉         Platform platform = Platform.get();         for (Method method : service.getDeclaredMethods()) { //遍歷WanApi方法             //不是默認方法,并且不是靜態方法             if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {                 //把方法提前加載進來(檢查下有沒有問題)                 loadServiceMethod(method);             }         }     } } 

如果開了validateEagerly,會一次性把接口WanApi的所有方法都檢查一遍并加載進來,可以在debug模式下開啟,提前發現錯誤寫法,比如在@GET請求設置了@Body這種錯誤就會拋出異常:

java.lang.IllegalArgumentException: Non-body HTTP method cannot contain @Body. 

3、loadServiceMethod

然后是loadServiceMethod(method).invoke(args),看名字可知是先找方法,然后執行

//Retrofit.java //緩存,用了線程安全ConcurrentHashMap final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>(); ServiceMethod<?> loadServiceMethod(Method method) {     ServiceMethod<?> result = serviceMethodCache.get(method);     //WanApi的articleList方法已緩存,直接返回     if (result != null) return result;     synchronized (serviceMethodCache) {         result = serviceMethodCache.get(method);         if (result == null) {             //解析articleList的注解,創建ServiceMethod并緩存起來             result = ServiceMethod.parseAnnotations(this, method);             serviceMethodCache.put(method, result);         }     }     return result; } 

跟進ServiceMethod.parseAnnotations

//ServiceMethod.java static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {     //1.     RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);     //檢查:articleList方法返回類型不能用通配符和void...     //2.     return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory); } 

4、 RequestFactory.parseAnnotations

//RequestFactory.java static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {     return new Builder(retrofit, method).build(); } class Builder {     RequestFactory build() {         //解析方法注解如GET         for (Annotation annotation : methodAnnotations) {             parseMethodAnnotation(annotation);         }         //省略各種檢查...         //解析參數注解如Path         int parameterCount = parameterAnnotationsArray.length;         parameterHandlers = new ParameterHandler<?>[parameterCount];         for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {             parameterHandlers[p] =                 parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);         }         //省略各種檢查...         return new RequestFactory(this);     } } 

得到RequestFactory后, HttpServiceMethod.parseAnnotations,HttpServiceMethod負責適配和轉換處理,將接口方法的調用調整為HTTP調用

//HttpServiceMethod.java //ResponseT響應類型如WanArticleBean,ReturnT返回類型如Call static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(     Retrofit retrofit, Method method, RequestFactory requestFactory) {     //省略kotlin協程邏輯...     Annotation[] annotations = method.getAnnotations();     //遍歷找到合適的適配器     CallAdapter<ResponseT, ReturnT> callAdapter =         createCallAdapter(retrofit, method, adapterType, annotations);     //得到響應類型,如WanArticleBean     Type responseType = callAdapter.responseType();     //遍歷找到合適的轉換器     Converter<ResponseBody, ResponseT> responseConverter =         createResponseConverter(retrofit, method, responseType);     okhttp3.Call.Factory callFactory = retrofit.callFactory;     return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); } 

5、最終返回了一個CallAdapted,看到CallAdapted

//CallAdapted extends HttpServiceMethod extends ServiceMethod class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {     private final CallAdapter<ResponseT, ReturnT> callAdapter;     CallAdapted(         RequestFactory requestFactory,         okhttp3.Call.Factory callFactory,         Converter<ResponseBody, ResponseT> responseConverter,         CallAdapter<ResponseT, ReturnT> callAdapter) {         super(requestFactory, callFactory, responseConverter);         this.callAdapter = callAdapter;     }     @Override     protected ReturnT adapt(Call<ResponseT> call, Object[] args) {         //適配器         return callAdapter.adapt(call);     } } 

回到Retrofit.Builder

//Retrofit.Builder.java public Retrofit build() {     Executor callbackExecutor = this.callbackExecutor;     //如果沒設置線程池,則給android平臺設置一個默認的MainThreadExecutor(用Handler將回調切回主線程)     if (callbackExecutor == null) {         callbackExecutor = platform.defaultCallbackExecutor();     }     List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);     //添加默認的DefaultCallAdapterFactory     callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor)); } 

DefaultCallAdapterFactory這個工廠創建具體的CallAdapter實例

//DefaultCallAdapterFactory.java public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {     final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);     //如果指定了SkipCallbackExecutor注解,就表示不需要切回主線程     final Executor executor =         Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)         ? null         : callbackExecutor;     return new CallAdapter<Object, Call<?>>() {         @Override         public Type responseType() {             return responseType;         }         @Override         public Call<Object> adapt(Call<Object> call) {             //默認情況下,返回用主線程池包裝的Call,他的enqueue會使用主線程池的execute             return executor == null ? call : new ExecutorCallbackCall<>(executor, call);         }     }; } 

6、invoke

前邊loadServiceMethod得到了CallAdapted,然后執行invoke,實現在父類HttpServiceMethod里,

//HttpServiceMethod.java final ReturnT invoke(Object[] args) {     //終于見到okhttp了!     Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);     return adapt(call, args); } class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {     private final CallAdapter<ResponseT, ReturnT> callAdapter;     @Override     protected ReturnT adapt(Call<ResponseT> call, Object[] args) {         //用前邊得到的適配器,把OkHttpCall包成ExecutorCallbackCall         return callAdapter.adapt(call);     } } 

然后是請求入隊,ExecutorCallbackCall.enqueue -> OkHttpCall.enqueue,

//ExecutorCallbackCall.java void enqueue(final Callback<T> callback) {     delegate.enqueue(         new Callback<T>() {             @Override             public void onResponse(Call<T> call, final Response<T> response) {                 //將回調切回主線程                 callbackExecutor.execute(                     () -> {                         callback.onResponse(ExecutorCallbackCall.this, response);                     });                 //...             }             @Override             public void onFailure(Call<T> call, final Throwable t) {}         }); } //OkHttpCall.java void enqueue(final Callback<T> callback) {     //okhttp邏輯     okhttp3.Call call;     call.enqueue(new okhttp3.Callback() {         void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {             callback.onResponse(OkHttpCall.this, response);         }     }) } 

到此整個流程就通了

二、功能擴展

1、OkHttpClient

Retrofit使用OkHttpClient來實現網絡請求,這個OkHttpClient雖然不能替換為其他的網絡執行框架比如Volley,但是Retrofit允許我們使用自己擴展OkHttpClient,一般最常擴展的就是Interceptor攔截器了;

OkHttpClient mClient = new OkHttpClient.Builder()                 .addInterceptor(new Interceptor() {                     @Override                     public Response intercept(Chain chain) throws IOException {                         try {                             Request.Builder builder = chain.request().newBuilder();                             builder.addHeader("Accept-Charset", "UTF-8");                             builder.addHeader("Accept", " application/json");                             builder.addHeader("Content-type", "application/json");                             Request request = builder.build();                             return chain.proceed(request);                         } catch (Exception e) {                             e.printStackTrace();                         }                         return null;                     }                 }).build(); Retrofit retrofit = new Retrofit.Builder()                 .baseUrl(Config.DOMAIN)                 .addConverterFactory(GsonConverterFactory.create())                 .client(mClient)                 .build(); 

2、addConverterFactory

擴展的是對返回的數據類型的自動轉換,把一種數據對象轉換為另一種數據對象;

GsonConverterFactory可以把Http訪問得到的json字符串轉換為Java數據對象BizEntity,這個BizEntity是在INetApiService接口中要求的的;

如果現有的擴展包不能滿足需要,可以繼承Retrofit的接口。retrofit2.Converter

在創建Retrofit對象時,可以插入我們自定義的ConverterFactory;

//retrofit對象 Retrofit retrofit=new Retrofit.Builder() .baseUrl(Config.DOMAIN) .addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(YourConverterFactory.create())//添加自定義Converter .build(); 

3、addCallAdapterFactory

擴展的是對網絡工作對象callWorker的自動轉換,把Retrofit中執行網絡請求的Call對象,轉換為接口中定義的Call對象;

這個轉換不太好理解,我們可以對照下圖來理解:

???

Retrofit本身用一個OkHttpCall的類負責處理網絡請求,而我們在接口中定義需要定義很多種Call,接口里的Call和Retrofit里的OkHttpCall并不一致,所以我們需要用一個CallAdapter去做一個適配轉換;

這其實是Retrofit非常核心,也非常好用的一個設計,如果我們在接口中要求的函數返回值是個RxJava的Flowable對象

public interface INetApiService {     @GET("/demobiz/api.php")     Flowable<BizEntity> getBizInfo(@Query("id") String id); } 

那么我們只需要為Retrofit添加對應的擴展;

//retrofit對象 Retrofit retrofit=new Retrofit.Builder() .baseUrl(Config.DOMAIN) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); 

就能得到Flowable類型的callWorker對象;

//用retrofit加工出對應的接口實例對象 INetApiService netApiService= retrofit.create(INetApiService.class); ··· //調用接口函數,獲得網絡工作對象 Flowable<BizEntity> callWorker= netApiService.getBizInfo("id001"); 在這里,callAdapter做的事情就是把retrofit2.Call對象適配轉換為Flowable<T>對象; 

同樣,如果現有的擴展包不能滿足需要,可以繼承Retrofit的接口;retrofit2.CallAdapter

4、動態替換url

在構建Retrofit時傳入HttpUrl對象,之后這個實例就一直存在不會更改,所以可以反射修改他的字段比如host,來實現動態替換服務端地址;

String SERVER = "https://www.xxx.com/"; HttpUrl httpUrl = HttpUrl.get(SERVER); Retrofit retrofit = new Retrofit.Builder()     //.baseUrl(SERVER)     .baseUrl(httpUrl) //使用HttpUrl     .build(); 

總結:

1.Retrofit將Http請求抽象成java接口

2.接口里用注解 描述和配置網絡請求參數




3.動態代理的方式來生成call對象。


責任編輯:武曉燕 來源: Android開發編程
相關推薦

2021-10-15 09:19:17

AndroidSharedPrefe分析源碼

2021-09-10 07:31:54

AndroidAppStartup原理

2021-08-24 07:53:28

AndroidActivity生命周期

2024-11-01 08:57:07

2021-09-17 06:55:50

AndroidLayoutView

2023-09-19 22:47:39

Java內存

2021-09-30 07:36:51

AndroidViewDraw

2022-09-05 22:22:00

Stream操作對象

2021-09-07 06:40:25

AndroidLiveData原理

2021-09-16 06:44:04

Android進階流程

2021-09-15 07:31:33

Android窗口管理

2014-07-15 17:17:31

AdapterAndroid

2021-09-24 08:10:40

Java 語言 Java 基礎

2017-08-08 09:15:41

前端JavaScript頁面渲染

2021-02-17 11:25:33

前端JavaScriptthis

2021-10-21 10:02:37

Java開發代碼

2021-10-10 13:31:14

Java負載均衡算法

2021-10-26 17:52:52

Android插件化技術

2016-10-26 20:49:24

ReactJavascript前端

2022-11-04 09:43:05

Java線程
點贊
收藏

51CTO技術棧公眾號

国内小视频在线看| 久久国内精品自在自线400部| 欧美mv日韩mv| 日本韩国在线视频| 亚洲国产精品99久久久久久久久| mm131午夜| 蜜臀av一区二区| 久久爱av电影| 精品1区2区3区4区| 亚洲va欧美va国产综合剧情| 都市激情亚洲| 久久精品视频亚洲| 亚洲最大网站| 亚洲精品国产精品久久清纯直播| 欧美激情黑人| 欧美日韩国产免费| jizz在线观看| 欧美日韩aaaaa| 九色在线免费| 91国产丝袜在线播放| 日韩av成人| 在线视频你懂得一区二区三区| 在线黄色.com| 色婷婷综合久色| av在线资源网| 日韩欧美一区二区视频| 婷婷丁香在线| 日韩精品在线观| 国产一区二区三区四区五区3d | 一区二区三区成人| 999www人成免费视频| 久久久久久影视| 那种视频在线观看| 国产欧美日韩综合精品一区二区| 亚洲福利精品视频| 亚洲欧美另类久久久精品2019| gogo人体高清视频| 亚洲午夜一区二区三区| 国产对白在线正在播放| 色一情一乱一乱一91av| 2021av在线| 欧美tickling网站挠脚心| a级大胆欧美人体大胆666| 亚洲国产成人精品电影| 亚洲欧美在线成人| 久久久这里只有精品视频| 九热爱视频精品视频| 国产精品麻豆va在线播放| 欧美a级片网站| 欧美重口乱码一区二区| 韩国精品在线观看| 三级a在线观看| 精品福利樱桃av导航| sm国产在线调教视频| 国产亚洲精品综合一区91| 久久成人福利| 91久久国产自产拍夜夜嗨| 美腿丝袜亚洲一区| 国产视频一区二区视频| 日韩欧美亚洲一二三区| 99爱在线观看| 91av在线免费观看| 亚洲欧美日韩国产| 凹凸国产熟女精品视频| 黑人狂躁日本妞一区二区三区| 中中文字幕av在线| 久久大大胆人体| 红桃视频国产一区| 欧美精品卡一卡二| 一区二区三区四区不卡视频| 国产福利第一视频在线播放| 亚洲视频专区在线| 精品国内自产拍在线观看视频 | 日韩av免费在线看| 夜夜嗨网站十八久久| 日韩小视频网站| 亚洲成av人片一区二区| www中文字幕在线观看| 国内成人精品视频| 久久精品天堂| 日韩中文字幕二区| 精品视频在线看| 欧美特黄不卡| 就去色蜜桃综合| 国产精品国产三级国产aⅴ无密码 国产精品国产三级国产aⅴ原创 | 国产精品扒开腿做爽爽爽的视频| 一区二区三区国产在线| 日本福利视频在线| 色婷婷久久99综合精品jk白丝 | 欧美高清激情brazzers| 国产精品白丝久久av网站| 亚洲一区二区三区成人在线视频精品| 精品一区二区三区免费视频| 最新日本视频| 国产亚洲精品91在线| 亚洲人体av| 99视频在线视频| 精品一区二区亚洲| 好吊日精品视频| 成人网18入口| 国产一区二区三区在线观看视频 | 亚洲精品一区av在线播放| 亚洲一区 二区 三区| 午夜欧美福利视频| 亚洲欧美国产视频| 另类图片国产| 欧洲毛片在线| 日本久久久久久久| 久久在线免费观看| 狠狠操一区二区三区| 国产精品一区在线播放| 亚洲高清免费观看| 国产成人澳门| 少妇性饥渴无码a区免费| 日韩欧美一区电影| 最新国产精品| 性欧美18+| 91国产中文字幕| 久久日一线二线三线suv| 亚洲最大成人| 日韩欧美一区二区视频在线播放| 色综合天天综合在线视频| 日韩mv欧美mv国产网站| 精品久久久噜噜噜噜久久图片 | 国产资源在线观看| 日韩av免费在线| 亚洲日本中文字幕区| 成人动漫视频| 日韩一级免费在线观看| 日韩一区二区av| 91一区二区在线观看| 51一区二区三区| www.日本少妇| 久久久久999| 97精品久久久午夜一区二区三区| 暖暖成人免费视频| 国产91在线亚洲| 中日韩美女免费视频网站在线观看 | 国产在线精品91| 亚洲欧美成人网| 另类综合日韩欧美亚洲| 日韩另类在线| 亚洲欧美日韩精品久久久| 精品国产污网站| 国产一区二区三区久久久| 亚洲欧美韩国| 干日本少妇首页| 欧美日韩免费| 爆操妹子视频在线观看| 韩国视频理论视频久久| 国产精品久久久久久久久免费丝袜| 国产精东传媒成人av电影| 777永久免费网站国产| 欧美亚洲国产日韩2020| 无吗不卡中文字幕| 欧美在线高清| 久cao在线| 亚洲图片在线观看| 在线免费看av不卡| 国产精品久久国产精麻豆99网站| 精品国产一区探花在线观看 | 国产精品久久激情| 午夜精品福利一区二区蜜股av | 国产97色在线| 色综合欧美在线| 久久精品天堂| 黄色欧美视频| 成人网18入口| 98国产高清一区| 欧美r级在线观看| 成人听书哪个软件好| 成人资源在线| 三级在线播放| 天堂av免费看| 91国在线精品国内播放| 在线精品亚洲一区二区不卡| 日韩中文字幕91| 亚洲精品自拍| 日色在线视频| 成年人免费观看的视频| 久久免费在线观看| 色悠悠久久综合| 韩国毛片一区二区三区| www.丝袜精品| 在线免费看黄| 日本中文字幕片| 国产精品传媒毛片三区| 视频直播国产精品| 色综合久久六月婷婷中文字幕| 九色|91porny| 精品一区二区三区中文字幕老牛| 男男gaygays亚洲| 高清中文字幕在线| 色综合久久久久久久久五月| 丝袜+亚洲+另类+欧美+变态| 欧美午夜三级| 欧美国产三级| 亚洲综合国产激情另类一区| 三级成人黄色影院| 在线观看免费观看在线91|