<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                [TOC] # Retrofit > A type-safe HTTP client for Android and Java 開發Android App肯定會使用Http請求與服務器通信,上傳或下載數據等。目前開源的Http請求工具也有很多,比如Google開發的`Volley`,loopj的`Android Async Http`,Square開源的`OkHttp`或者`Retrofit`等。 我覺得Retrofit 無疑是這幾個當中最好用的一個,設計這個庫的思路很特別而且巧妙。Retrofit的代碼很少,花點時間讀它的源碼肯定會收獲很多。 本文的源碼分析基于Retrofit 2,和Retrofit 1.0的Api有較大的不同, 本文主要分為幾部分:`Retrofit 使用`,`Retrofit 源碼分析` ## Retroift 使用 ### 官方使用簡介 > 官方使用簡介:(http://square.github.io/retrofit/) ### 引用依賴 ``` // 最新版本 :2.5.0 implementation 'com.squareup.retrofit2:retrofit:(insert latest version)' ``` ### 生成一個ApiService ```java public interface GitHubService { @GET("users/{user}/repos") Call<List<Repo>> listRepos(@Path("user") String user); } ``` ### 創建Retorfit ```java Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .build(); GitHubService service = retrofit.create(GitHubService.class); ``` ### 發起請求 ```java Call<List<Repo>> repos = service.listRepos("octocat"); //異步請求 // 請求數據,并且處理response call.enqueue(new Callback<List<Repo>>() { @Override public void onResponse(Response<List<Repo>> response) { System.out.println(response); } @Override public void onFailure(Throwable t) { } }); //同步請求 call.execute() ``` ### ApiService 配置 #### Url配置 | 注解 | 描述 | 實例 | | --- | --- | --- | | @GET | get請求 | @GET("group/users") | | @POST | post請求 | @POST("group/users") | | @Uri | uri全連接配合 其他請求方法 | @Uri("http://xxxx/group/users") | | @PATH | get/post 請求的動態路徑,用于方法參數注解 | @GET("group/{id}/users" ? ?Call<List<User>> groupList(@Path("id") int groupId); | | @Headers | 請求的 HEADER 作用于方法 | @Headers("Cache-Control: max-age=640000") | | @Header | 請求的 HEADER 作用于方法參數 | @Header("Authorization") String authorization | | @Query & @QueryMap | 用于方法參數注解,只能配合@GET | Call<List<User>> groupList(@Path("id") int groupId,@Query("sort") String sort); | | @Body | 用于方法參數注解 | @POST("users/new")Call<User> createUser(@Body User user); | | @Field & @FieldMap | 用于方法參數注解,只能配合@POST | 類似@Query & @QueryMap | | @Part & @PartMap | 用于POST文件上傳 |Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);| ### 其他高級用法 官方使用簡介:(http://square.github.io/retrofit/) ## Retrofit 源碼分析 > retrofit的最大特點就是解耦,要解耦就需要大量的設計模式,假如一點設計模式都不懂的人,可能很難看懂retrofit。 ### 基本流程(組裝過程) #### Retrofit#create ```java ApiService service = retrofit.create(ApiService.class); ``` Retrofit是如何創建Api的,是通過`Retrofit#create()`的方法 ,通過[動態代理](https://www.cnblogs.com/gonjan-blog/p/6685611.html)方式。 關于動態代理 這里就不多講了,樓下有動態代理鏈接,至于為什么用動態代理,大家想一想??? ```java public <T> T create(final Class<T> service) { Utils.validateServiceInterface(service); if (validateEagerly) { eagerlyValidateMethods(service); } return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { private final Platform platform = Platform.get(); @Override public Object invoke(Object proxy, Method method, Object... args) throws Throwable { // If the method is a method from Object then defer to normal invocation. if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } //DefaultMethod 是 Java 8 的概念,是定義在 interface 當中的有實現的方法 if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); } //每一個接口最終實例化成一個 ServiceMethod,并且會緩存 ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method); //Retrofit 與 OkHttp 完全耦合 OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); //發起請求,并解析服務端返回的結果 return serviceMethod.adapt(okHttpCall); } }); } ``` 提取在create方法中的關鍵幾行代碼 `Service Proxy` 當大家了解了動態代理之后, 都知道我們調用ApiService中的`method`都會自動調用 `InvocationHandler()`. 真真開始執行的是 `serviceMethod.adapt(okHttpCall)==> calladapter#adapt(okhttpCall);` ```java ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method); OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.adapt(okHttpCall); ``` 一個 ServiceMethod 對象對應于一個 API interface 的一個方法,loadServiceMethod(method) 方法負責加載 ServiceMethod: ```java ServiceMethod<?, ?> loadServiceMethod(Method method) { ServiceMethod<?, ?> result = serviceMethodCache.get(method); if (result != null) return result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { result = new ServiceMethod.Builder<>(this, method).build(); serviceMethodCache.put(method, result); } } return result; } ``` 這里實現了緩存邏輯,同一個 API 的同一個方法,只會創建一次。這里由于我們每次獲取 API 實例都是傳入的 class 對象,而 class 對象是進程內單例的,所以獲取到它的同一個方法 Method 實例也是單例的,所以這里的緩存是有效的。 `ServiceMethod`是什么呢???里面包含什么 ??? 大致就是想這個方法的method轉化成 `ServiceMethod對象` 包含 各個注解(方法的注解,參數的注解,方法的返回值的東西),那我們來看下具體有什么東西 我們看看 `ServiceMethod` 的構造函數: ```java ServiceMethod(Builder<R, T> builder) { this.callFactory = builder.retrofit.callFactory(); this.callAdapter = builder.callAdapter; this.baseUrl = builder.retrofit.baseUrl(); this.responseConverter = builder.responseConverter; this.httpMethod = builder.httpMethod; this.relativeUrl = builder.relativeUrl; this.headers = builder.headers; this.contentType = builder.contentType; this.hasBody = builder.hasBody; this.isFormEncoded = builder.isFormEncoded; this.isMultipart = builder.isMultipart; this.parameterHandlers = builder.parameterHandlers; } ``` 這里用了buider 模式,這里很多參數,有的參數一看就明白 像baseUrl,headers ,contyentType等,講解主要關注四個成員:callFactory,callAdapter,responseConverter 和 parameterHandlers。 + callFactory 負責創建 HTTP 請求,HTTP 請求被抽象為了 okhttp3.Call 類,它表示一個已經準備好,可以隨時執行的 HTTP 請求; + callAdapter 把 retrofit2.Call<T> 轉為 T(注意和 okhttp3.Call 區分開來,retrofit2.Call<T> 表示的是對一個 Retrofit 方法的調用),這個過程會發送一個 HTTP 請求,拿到服務器返回的數據(通過 okhttp3.Call 實現),并把數據轉換為聲明的 T 類型對象(通過 Converter<F, T> 實現); + responseConverter 是 Converter<ResponseBody, T> 類型,負責把服務器返回的數據(JSON、XML、二進制或者其他格式,由 ResponseBody 封裝)轉化為 T 類型的對象; + parameterHandlers 則負責解析 API 定義時每個方法的參數,并在構造 HTTP 請求時設置參數; `retrofit2.ServiceMethod.Builder#build()`方法中生成了以上對象 ```java public ServiceMethod build() { // 通過method 找到對應的retrofit2.CallAdapter callAdapter = createCallAdapter(); //省略代碼... // 通過method 找到對應的retrofit2.Converter responseConverter = createResponseConverter(); //省略代碼... for (Annotation annotation : methodAnnotations) { //解析 請求的方法 parseMethodAnnotation(annotation); } int parameterCount = parameterAnnotationsArray.length; parameterHandlers = new ParameterHandler<?>[parameterCount]; for (int p = 0; p < parameterCount; p++) { Type parameterType = parameterTypes[p]; //省略代碼... Annotation[] parameterAnnotations = parameterAnnotationsArray[p]; ... //解析方法參數注解 parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations); } //省略代碼... return new ServiceMethod<>(this); } ``` ### CallAdapter > retrofit2.Retrofit.Builder#addCallAdapterFactory(Factory) 默認 retrofit2.DefaultCallAdapterFactory 使用的是OkhttpCall + `retrofit2.ServiceMethod.Builder#createCallAdapter(...)` + `retrofit2.Retrofit#callAdapter(...)` + `retrofit2.Retrofit#nextCallAdapter(null,...)` ```java public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) { checkNotNull(returnType, "returnType == null"); checkNotNull(annotations, "annotations == null"); int start = callAdapterFactories.indexOf(skipPast) + 1; for (int i = start, count = callAdapterFactories.size(); i < count; i++) { // 調用retrofit2.CallAdapter.Factory#get CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this); if (adapter != null) { return adapter; } } //省略代碼 //throw new IllegalArgumentException(builder.toString()); } ``` 上面知道如果注冊了多個`retrofit2.CallAdapter`,按照注冊的順序來執行,如果那個有返回值就會直接返回,不走for循環了 ### Converter > 通過Retrofit 添加ConverterFactory `Retrofit.Builder#addConverterFactory(Factory)` 默認`retrofit2.BuiltInConverters` #### ParameterHandlers or RequestConverter + `retrofit2.ServiceMethod.Builder#parseParameter(...)` + `retrofit2.ServiceMethod.Builder#parseParameterAnnotation(...)` + `retrofit2.Retrofit#stringConverter(...)` + `retrofit2.Converter.Factory#stringConverter(...)` + OR `retrofit2.Converter.Factory#requestBodyConverter(...)` ```java private ParameterHandler<?> parseParameter( int p, Type parameterType, Annotation[] annotations) { ParameterHandler<?> result = null; for (Annotation annotation : annotations) { //關鍵代碼 ParameterHandler<?> annotationAction = parseParameterAnnotation( p, parameterType, annotations, annotation); if (annotationAction == null) { continue; } //省略代碼 ... result = annotationAction; } //省略代碼 ... return result; } private ParameterHandler<?> parseParameterAnnotation(int p, Type type, Annotation[] annotations, Annotation annotation) { // 關鍵代碼 Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations); // or Converter<?, RequestBody> converter = retrofit.requestBodyConverter(type, annotations, methodAnnotations); return new ParameterHandler; } ``` 【總結】: 當執行`retrofit2.Retrofit#create(final Class<T> service)`的時候就會找到對應的 `retrofit2.Converter` #### responseConverter + `retrofit2.ServiceMethod.Builder#createResponseConverter(...)` + `retrofit2.Retrofit#responseBodyConverter(...)` + `retrofit2.Retrofit#nextResponseBodyConverter(null,...)` ```java public <T> Converter<ResponseBody, T> nextResponseBodyConverter( @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) { checkNotNull(type, "type == null"); checkNotNull(annotations, "annotations == null"); int start = converterFactories.indexOf(skipPast) + 1; for (int i = start, count = converterFactories.size(); i < count; i++) { // 調用 retrofit2.Converter.Factory#responseBodyConverter Converter<ResponseBody, ?> converter = converterFactories.get(i).responseBodyConverter(type, annotations, this); if (converter != null) { //noinspection unchecked return (Converter<ResponseBody, T>) converter; } } ... //省略代碼 // throw new IllegalArgumentException(...) } ``` 上面知道如果注冊了多個Converter 按照注冊的順序來執行,如果那個有返回值就會直接返回,不走for循環了 【總結】: 當執行`retrofit2.Retrofit#create(final Class<T> service)`的時候就會找到對應的 `retrofit2.Converter` **以上都是初始化操作,將所有的請求相關的東西都封裝到`ServiceMethod`中** ### 執行過程 ```java serviceMethod.adapt(okHttpCall); ``` 真正執行的開始點就是`serviceMethod.adapt` ,**ServiceMethod.class**執行過程中的 三個很重要,也是整個過程關鍵節點 ```java // 簡單粗俗的講:返回包裝okhttpCall后的對象 T adapt(Call<R> call) { return callAdapter.adapt(call); } //retrofit2.OkHttpCall#createRawCall 調用 okhttp3.Call toCall(@Nullable Object... args) throws IOException { // 返回 okhttp.Call } //retrofit2.OkHttpCall 請求結果之后 會調用 responseBody convert R toResponse(ResponseBody body) throws IOException { return responseConverter.convert(body); } ``` **通過`serviceMethod`上面三個方法,將 `OkhttpCall`,`CallAdapter` ,`Converter` 關聯起來** ![](https://ws1.sinaimg.cn/large/882b6a2aly1g0hirf70mqj20or0nen2d.jpg) 為什么要用動態代理? 因為對接口的所有方法的調用都會集中轉發到 InvocationHandler#invoke函數中,我們可以集中進行處理,更方便了。你可能會想,我也可以手寫這樣的代理類,把所有接口的調用都轉發到 InvocationHandler#invoke,當然可以,但是可靠地自動生成豈不更方便,可以方便為什么不方便。 [Retrofit分析-漂亮的解耦套路](https://www.jianshu.com/p/45cb536be2f4) [Java動態代理](http://a.codekk.com/detail/Android/Caij/%E5%85%AC%E5%85%B1%E6%8A%80%E6%9C%AF%E7%82%B9%E4%B9%8B%20Java%20%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看