激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Android - Android源碼進階之深入理解Retrofit工作原理

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

2021-09-08 22:45Android開發編程 Android

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

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

前言

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

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

一、使用Retrofit

1、包引用

在gradle文件中引用retrofit

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

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

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

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

2、定義接口

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

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

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

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

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

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

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

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

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

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

4、訪問網絡數據

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

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

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

二、Retrofit實現原理

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

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

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

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

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

2、validateServiceInterface驗證邏輯

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

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

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

3、loadServiceMethod

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

  1. //Retrofit.java 
  2. //緩存,用了線程安全ConcurrentHashMap 
  3. final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>(); 
  4. ServiceMethod<?> loadServiceMethod(Method method) { 
  5.     ServiceMethod<?> result = serviceMethodCache.get(method); 
  6.     //WanApi的articleList方法已緩存,直接返回 
  7.     if (result != nullreturn result; 
  8.     synchronized (serviceMethodCache) { 
  9.         result = serviceMethodCache.get(method); 
  10.         if (result == null) { 
  11.             //解析articleList的注解,創建ServiceMethod并緩存起來 
  12.             result = ServiceMethod.parseAnnotations(this, method); 
  13.             serviceMethodCache.put(method, result); 
  14.         } 
  15.     } 
  16.     return result; 

跟進ServiceMethod.parseAnnotations

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

4、 RequestFactory.parseAnnotations

  1. //RequestFactory.java 
  2. static RequestFactory parseAnnotations(Retrofit retrofit, Method method) { 
  3.     return new Builder(retrofit, method).build(); 
  4. class Builder { 
  5.     RequestFactory build() { 
  6.         //解析方法注解如GET 
  7.         for (Annotation annotation : methodAnnotations) { 
  8.             parseMethodAnnotation(annotation); 
  9.         } 
  10.         //省略各種檢查... 
  11.         //解析參數注解如Path 
  12.         int parameterCount = parameterAnnotationsArray.length; 
  13.         parameterHandlers = new ParameterHandler<?>[parameterCount]; 
  14.         for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) { 
  15.             parameterHandlers[p] = 
  16.                 parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter); 
  17.         } 
  18.         //省略各種檢查... 
  19.         return new RequestFactory(this); 
  20.     } 

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

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

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

  1. //CallAdapted extends HttpServiceMethod extends ServiceMethod 
  2. class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> { 
  3.     private final CallAdapter<ResponseT, ReturnT> callAdapter; 
  4.     CallAdapted( 
  5.         RequestFactory requestFactory, 
  6.         okhttp3.Call.Factory callFactory, 
  7.         Converter<ResponseBody, ResponseT> responseConverter, 
  8.         CallAdapter<ResponseT, ReturnT> callAdapter) { 
  9.         super(requestFactory, callFactory, responseConverter); 
  10.         this.callAdapter = callAdapter; 
  11.     } 
  12.     @Override 
  13.     protected ReturnT adapt(Call<ResponseT> call, Object[] args) { 
  14.         //適配器 
  15.         return callAdapter.adapt(call); 
  16.     } 

回到Retrofit.Builder

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

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

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

6、invoke

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

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

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

  1. //ExecutorCallbackCall.java 
  2. void enqueue(final Callback<T> callback) { 
  3.     delegate.enqueue( 
  4.         new Callback<T>() { 
  5.             @Override 
  6.             public void onResponse(Call<T> call, final Response<T> response) { 
  7.                 //將回調切回主線程 
  8.                 callbackExecutor.execute
  9.                     () -> { 
  10.                         callback.onResponse(ExecutorCallbackCall.this, response); 
  11.                     }); 
  12.                 //... 
  13.             } 
  14.             @Override 
  15.             public void onFailure(Call<T> call, final Throwable t) {} 
  16.         }); 
  17. //OkHttpCall.java 
  18. void enqueue(final Callback<T> callback) { 
  19.     //okhttp邏輯 
  20.     okhttp3.Call call; 
  21.     call.enqueue(new okhttp3.Callback() { 
  22.         void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) { 
  23.             callback.onResponse(OkHttpCall.this, response); 
  24.         } 
  25.     }) 

到此整個流程就通了

二、功能擴展

1、OkHttpClient

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

  1. OkHttpClient mClient = new OkHttpClient.Builder() 
  2.                 .addInterceptor(new Interceptor() { 
  3.                     @Override 
  4.                     public Response intercept(Chain chain) throws IOException { 
  5.                         try { 
  6.                             Request.Builder builder = chain.request().newBuilder(); 
  7.                             builder.addHeader("Accept-Charset""UTF-8"); 
  8.                             builder.addHeader("Accept"" application/json"); 
  9.                             builder.addHeader("Content-type""application/json"); 
  10.                             Request request = builder.build(); 
  11.                             return chain.proceed(request); 
  12.                         } catch (Exception e) { 
  13.                             e.printStackTrace(); 
  14.                         } 
  15.                         return null
  16.                     } 
  17.                 }).build(); 
  18. Retrofit retrofit = new Retrofit.Builder() 
  19.                 .baseUrl(Config.DOMAIN) 
  20.                 .addConverterFactory(GsonConverterFactory.create()) 
  21.                 .client(mClient) 
  22.                 .build(); 

2、addConverterFactory

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

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

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

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

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

3、addCallAdapterFactory

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

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

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

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

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

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

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

  1. //retrofit對象 
  2. Retrofit retrofit=new Retrofit.Builder() 
  3. .baseUrl(Config.DOMAIN) 
  4. .addConverterFactory(GsonConverterFactory.create()) 
  5. .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) 
  6. .build(); 

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

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

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

4、動態替換url

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

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

總結:

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

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

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

原文鏈接:https://mp.weixin.qq.com/s/diT6tn3EGO41r-b7TAJ8Yg

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 一本免费视频 | 羞羞视频2023 | 青草久久久久 | 久久69精品久久久久久国产越南 | 香蕉久草在线 | 激情夜色 | 毛片在哪里看 | 欧美特黄a | 在线a视频 | 污黄视频在线播放 | 国产精品免费麻豆入口 | 午夜视频福利 | 香蕉久草视频 | 欧美性黄 | 欧美成人黄色片 | 女18一级大黄毛片免费女人 | 亚洲精品v天堂中文字幕 | 羞羞视频一区 | 国产做爰 | 一区二区精品在线 | 一级全毛片 | 日本高清视频网站www | 国产精品手机在线亚洲 | 久草影音| 久久成人福利 | 日本免费不卡一区二区 | 欧美日韩免费观看视频 | 久久综合久久美利坚合众国 | 久久久久久久久久久久久久av | 色婷婷综合久久久中文一区二区 | 日本aaaa片毛片免费观蜜桃 | 亚洲国产女同久久 | 亚洲视频黄 | 日本在线观看高清完整版 | 精品二区在线观看 | 国产日韩a | 免费欧美精品 | 亚洲欧美在线视频免费 | 四季久久免费一区二区三区四区 | 国产资源视频在线观看 | 久久久久久久久浪潮精品 |