主流開源框架之Retrofit深刻了解

上一篇咱們分析了主流的開源框架的源碼的第一篇OkHttp3,如今咱們來分析一下本系列第二篇——Retrofit2(源碼以2.6.1版爲準)。java

代理模式,可參考本人第一篇文章:Binder機制之AIDLandroid

OkHttp的源碼分析,可參考上一篇:主流開源框架之OkHttp3深刻了解編程

基本瞭解

1. 概念瞭解:

Retrofit2是基於OkHttp的一個Restful Api請求工具,它是一個類型安全的http客戶端請求工具(Type-safe HTTP client for Android and Java ),上一篇文章 [主流開源框架之OkHttp3深刻了解] 咱們已經瞭解OkHttp的機制和源碼,這裏咱們就來講說Retrofit2了,從功能上來講,Retrofit有點相似Volley,可是使用方式上相對而言Retrofit會更簡單,咱們來看一張圖: json

咱們的應用程序(即:「Application Layer」層) 經過Retrofti Layer層來封裝咱們的請求參數、header頭部和url等配置信息,而後交給OkHttp Layer層完成後續的請求操做。等服務端Server層將數據返回給OkHttp Layer層後又會將原始結果返回到Retrofit Layer層,最後由Retrofit Layer層返回給咱們的應用層。 而Retrofit2已經內置了OkHttp,這樣Retrofit就能夠專一於接口的封裝操做,而讓OkHttp專一於網絡請求的高效操做,二者分工合做更能提升效率。設計模式

總結:api

  1. App應用程序經過Retrofit請求網絡,其實是使用Retrofit層封裝請求參數,以後交由OkHttp執行後續的請求操做
  2. 服務端返回數據後,OkHttp將原始數據交給Retrofit層,Retrofit會根據開發者的須要對結果進行解析,而後返回解析後的數據

2. 基本使用:

public interface ApiService {
    @GET("api")
    Call<ResultBean> getResult(@Query("param") String param);
}

Retrofit RETROFIT_CLIENT = new Retrofit.Builder()
    // 設置baseUrl,緊急baseUrl結尾必定要帶「/」,不然會有異常的哦
    .baseUrl(BASE_URL)
    .client(OkHttpHolder.OK_HTTP_CLIENT)
    // 直接返回String類型需引入:ScalarsConverterFactory.create()
    // 添加響應數據轉換器工廠,這裏是Gson將得到響應結果轉換成Gson對象
    .addConverterFactory(GsonConverterFactory.create())
    // 添加網絡請求適配器工廠,這裏是RxJava2將Call轉換成Rxjava中的Observable
//    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .build();

// 建立接口實例
ApiService service = RETROFIT_CLIENT.create(ApiService.class);
// 調用接口中方法獲取Call對象,此Call並不是OkHttp中的Call,
// 而是Retrofit對OkHttp中的Call進行封裝的,所以使用此Call的同步/異步請求實際上就是使用OkHttp中的Call
Call<ResultBean> call = service.getResult("param");

// 發送同步請求
call.execute();
// 發送異步請求
call.enqueue(new Callback<ResultBean>() {
     @Override
     public void onResponse(Call<ResultBean> call, Response<ResultBean> response) {
        // 主線程
        String responseStr = response.body().toString();
        Log.e("result", responseStr);
    }

    @Override
    public void onFailure(Call<ResultBean> call, Throwable t) {
        // 主線程
        Log.e("result", t.getMessage());
    }
});
複製代碼

從使用上來看,Retrofit2仍是挺簡單的,不過要注意這兩個配置:數組

// 添加響應數據轉換器工廠,這裏是Gson將得到響應結果轉換成Gson對象
.addConverterFactory(GsonConverterFactory.create())
// 添加網絡請求適配器工廠,這裏是RxJava2將Call轉換成Rxjava中的Observable
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
複製代碼

這裏的ConverterFactory表示數據轉換器工廠,就是將接收到的響應結果數據轉換成想要的類型,例如通常使用Gson來解析服務器返回的數據,這裏就添加了一個GsonConverterFactory。CallAdapterFactory表示的是網絡請求適配器的工廠,它對應的是接口請求方法的返回類型,是將默認的ExecutorCallbackCall轉換成適配其它不一樣平臺所須要的類型。例如這裏添加了RxJava的適配器,那麼接口中就能夠寫成如下這樣,返回一個RxJava中的Observable類型。緩存

@GET("api")
 Observable<ResultBean> getResult(@Query("param") String param);
複製代碼

Retrofit網絡通信步驟:

  1. 建立retrofit實例
  2. 定義一個網絡請求接口併爲接口中的方法添加註釋(基本使用中已完成)
  3. 經過動態代理生成請求對象
  4. 經過 網絡請求適配器 將 網絡請求對象 進行平臺適配
  5. 經過 網絡請求執行器 發送網絡請求
  6. 經過 數據轉換器 解析數據
  7. 經過 回調執行器 切換線程
  8. 開發者在主線程處理返回數據

建立Retrofit

1. retrofit的成員屬性

/**
     * ConcurrentHashMap:一個線程安全的、支持高效併發的HashMap;
     *  Key 是 Method,Value 是 ServiceMethod。
     *  Method:就是上面接口中定義的getResult,這個方法中有不少註解:@GET、@Path、@Query等
     *  ServiceMethod:是將Method方法中全部的註解,解析後的對象就是ServiceMethod
     * serviceMethodCache:主要是用於緩存ServiceMethod,好比說緩存ServiceMethod中一些網絡請求的相關配置、網絡請求的方法、數據轉換器和網絡請求適配器等等
     */
    private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
    // Retrofit2中默認使用OkHttp,callFactory實際上就是OkHttpClient
    final okhttp3.Call.Factory callFactory;
    // 網絡請求url的基地址
    final HttpUrl baseUrl;
    // 數據轉換器工廠集合
    final List<Converter.Factory> converterFactories;
    // 網絡請求適配器工廠集合
    final List<CallAdapter.Factory> callAdapterFactories;
    // Executor,這是個網絡請求回調執行者,就是用來切換線程的
    final @Nullable Executor callbackExecutor;
    // 一個標誌位,是否當即解析網絡請求接口中的方法(即ApiService中的方法)
    final boolean validateEagerly;
複製代碼

2. retrofit的Builder

// Retrofit.Builder類:
    public static final class Builder {
        // retrofit適配的平臺:Android、Java8
        private final Platform platform;
        // 一下成員和第一部分【retrofit的成員屬性】中講解的同樣
        private @Nullable
        okhttp3.Call.Factory callFactory;
        private HttpUrl baseUrl;
        private final List<Converter.Factory> converterFactories = new ArrayList<>();
        private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
        private @Nullable
        Executor callbackExecutor;
        private boolean validateEagerly;

        Builder(Platform platform) {
            this.platform = platform;
        }

        public Builder() {
            this(Platform.get());
        }
        
        ......
        
    }
複製代碼

從Builder的成員中咱們看到了一個陌生的屬性 Platform,這個 Platform 很重要,是獲取當前須要適配的平臺。咱們經過 Builder 的構造函數能夠知道,調用了 Platform.get()方法,而後賦值給本身的 platform 變量。安全

class Platform {
    private static final Platform PLATFORM = findPlatform();

    static Platform get() {
        return PLATFORM;
    }

    private static Platform findPlatform() {
        try {
            Class.forName("android.os.Build");
            if (Build.VERSION.SDK_INT != 0) {
                return new Android();
            }
        } catch (ClassNotFoundException ignored) {
        }
        try {
            Class.forName("java.util.Optional");
            return new Java8();
        } catch (ClassNotFoundException ignored) {
        }
        return new Platform();
    }

    ......

    static class Android extends Platform {
        @IgnoreJRERequirement // Guarded by API check.
        @Override
        boolean isDefaultMethod(Method method) {
            // Api < 24 直接返回false
            if (Build.VERSION.SDK_INT < 24) {
                return false;
            }
            /**
             * method.isDefault() 判斷該方法是否爲默認方法
             * 默認方法是什麼?
             *  Java 8 新增了接口的默認方法。
             *  簡單說,默認方法就是接口能夠有實現方法,並且不須要實現類去實現其方法。
             *  咱們只需在方法名前面加個 default 關鍵字便可實現默認方法。
             * 所以咱們網絡請求接口中通常定義的都不是默認方法
             */
            return method.isDefault();
        }
    
        // 默認回調執行程序,用來切換線程
        @Override
        public Executor defaultCallbackExecutor() {
            return new MainThreadExecutor();
        }
    
        // 默認的網絡請求適配器
        @Override
        List<? extends CallAdapter.Factory> defaultCallAdapterFactories(@Nullable Executor callbackExecutor) {
            if (callbackExecutor == null) throw new AssertionError();
            DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
            // 根據SDK大小返回適配器集合
            return Build.VERSION.SDK_INT >= 24
                    // 僅在CompletableFuture(異步函數式編程)可用時添加(即:Java 8+ / Android API 24+)
                    ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
                    : singletonList(executorFactory); // 返回僅包含指定對象的不可變列表。 返回的列表是可序列化的。
        }
    
        // 默認調用適配器工廠大小
        @Override
        int defaultCallAdapterFactoriesSize() {
            return Build.VERSION.SDK_INT >= 24 ? 2 : 1;
        }
    
        // 默認轉換器工廠
        @Override
        List<? extends Converter.Factory> defaultConverterFactories() {
            return Build.VERSION.SDK_INT >= 24
                    // 僅在Optional(Java8爲了解決null值判斷問題)可用時添加(即:Java 8+ / Android API 24+)。
                    ? singletonList(OptionalConverterFactory.INSTANCE)
                    : Collections.<Converter.Factory>emptyList(); // 返回空集合
        }
    
        // 默認轉換器工廠大小
        @Override
        int defaultConverterFactoriesSize() {
            return Build.VERSION.SDK_INT >= 24 ? 1 : 0;
        }
        
        // 主線程執行器,內部使用Handler
        static class MainThreadExecutor implements Executor {
            private final Handler handler = new Handler(Looper.getMainLooper());
    
            @Override
            public void execute(Runnable r) {
                handler.post(r);
            }
        }
    }
}
複製代碼

get 方法會去調用findPlatform方法,經過Class.forName反射查找"android.os.Build"或者"java.util.Optional"並返回不一樣平臺的platform對象,咱們分析 Android 平臺,因此會返回一個Android()對象。咱們在Android對象中看到幾個方法:bash

  • defaultCallbackExecutor:默認回調執行器,其return 一個 MainThreadExecutor對象,能夠看出MainThreadExecutor裏面使用了Handler,所以咱們最終切換線程使用的仍是Handler。
  • defaultCallAdapterFactories:默認的網絡請求適配器,用於發送網絡請求,並將回調函數切換回主線程,從源碼中能夠看出若api>= 24,即支持函數式編程,則會多添加一個適配器CompletableFutureCallAdapterFactory
  • defaultConverterFactories:默認轉換器工廠,若api> 24,即支持函數式編程,則會多添加轉換器工廠OptionalConverterFactory
  • isDefaultMethod:判斷接口中的方法是否爲默認方法,通常都不是默認方法,只要該方法不被default 關鍵字標識而且帶有方法體,則該方法就不是默認方法,所以通常返回false

接下來咱們看一下build()方法:

// Retrofit.Builder類:
    public static final class Builder {
        
        ......
        
        public Retrofit build() {
        // baseUrl不可空
        if (baseUrl == null) {
            throw new IllegalStateException("Base URL required.");
        }

        // 若請求網絡工廠爲空,會默認配置爲 OkHttpClient
        // "此處證時【retrofit的成員屬性】中所說 callFactory 實際上就是OkHttpClient"
        okhttp3.Call.Factory callFactory = this.callFactory;
        if (callFactory == null) {
            callFactory = new OkHttpClient();
        }

        // 若沒配置回調執行器,則默認配置爲Platform 的defaultCallbackExecutor,
        // 上面咱們以前分析過defaultCallbackExecutor,它所返回的就是 MainThreadExecutor
        Executor callbackExecutor = this.callbackExecutor;
        if (callbackExecutor == null) {
            callbackExecutor = platform.defaultCallbackExecutor();
        }

        // 添加默認的網絡請求適配器,先添加開發者本身add的,後添加平臺默認的
        List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
        callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
        
        List<Converter.Factory> converterFactories = new ArrayList<>(
                1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

        // 首先添加內置(默認)轉換器工廠,後添加開發者本身add的,若此時Api>24,則最後還會添加默認的轉換器工廠
        converterFactories.add(new BuiltInConverters());
        converterFactories.addAll(this.converterFactories);
        converterFactories.addAll(platform.defaultConverterFactories());

        return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
                unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
    }
複製代碼

baseUrl異常問題

咱們多說一句,上面基本使用時咱們提到過baseUrl結尾要爲「/」,不然會拋異常,那麼咱們就來看一下baseUrl的構建:

// Retrofit.Builder類:
    public Builder baseUrl(String baseUrl) {
      checkNotNull(baseUrl, "baseUrl == null");
      return baseUrl(HttpUrl.get(baseUrl));
    }
    
    public Builder baseUrl(HttpUrl baseUrl) {
        checkNotNull(baseUrl, "baseUrl == null");
        List<String> pathSegments = baseUrl.pathSegments();
        if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
            throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
        }
        this.baseUrl = baseUrl;
        return this;
    }
複製代碼

baseUrl方法實現很是簡單就是將baseUrl設置到Retrofit.Builder中,參數類型爲String的方法將傳入的字符串封裝成了一個HttpUrl對象,調用對應重載方法,重載方法中調用pathSegments方法將url分割,而後判斷url是不是以斜槓結尾,不是則拋出異常。

至此,咱們的Retrofit就構建完成了。

Retrofit.create(經過動態代理生成請求對象)

// Retrofit類:
    public <T> T create(final Class<T> service) {
        // 驗證服務接口
        Utils.validateServiceInterface(service);
        // 熟不熟悉,驚不驚喜,咱們在【retrofit的成員屬性】中說過,validateEagerly爲是否當即解析網絡請求接口中的方法
        if (validateEagerly) {
            // 從名字能夠看出,「熱切地驗證方法」,所以就是當即解析請求接口「ApiService」中的方法
            eagerlyValidateMethods(service);
        }
        
        // retrofit的精華之一:動態代理模式
        return (T) Proxy.newProxyInstance(service.getClassLoader()
            , new Class<?>[]{service},new InvocationHandler() {
                    // 獲取到當前的平臺
                    private final Platform platform = Platform.get();
                    private final Object[] emptyArgs = new Object[0];

                    @Override
                    public @Nullable
                    Object invoke(Object proxy, Method method,@Nullable Object[] args) throws Throwable {
                        // 若是方法是來自Object的方法,則遵循正常調用
                        if (method.getDeclaringClass() == Object.class) {
                            return method.invoke(this, args);
                        }
                        // 若是該方法是默認方法,則直接調用默認方法
                        if (platform.isDefaultMethod(method)) {
                            return platform.invokeDefaultMethod(method, service, proxy, args);
                        }
                        // 加載網絡請求接口方法,並執行該方法
                        return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
                    }
                });
    }

    private void eagerlyValidateMethods(Class<?> service) {
        // 獲取當前平臺對象
        Platform platform = Platform.get();
        // 經過接口字節碼class類獲取全部 「聲明的方法」
        for (Method method : service.getDeclaredMethods()) {
            // 咱們上面【retrofit的Builder】中
            // 講解到通常網絡請求接口中都不是默認方法,而且也不會是靜態方法,所以此if判斷爲 true
            if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
                // 加載解析請求接口中的方法,該方法後續詳細講解
                loadServiceMethod(method);
            }
        }
    }
複製代碼

此方法就是Retrofit設計的精髓之一,採用了外觀模式和動態代理模式,而且建立了API接口的實例。此方法涉及的邏輯有點多,先來總結一下:

  1. 首先判斷validateEagerly標識,默認爲false,若爲true,則先進入eagerlyValidateMethods方法,此方法循環遍歷了做爲參數傳入的網絡請求接口類中全部聲明的方法,而且判斷每一個方法既不是默認方法也不是靜態方法就調用loadServiceMethod方法去加載這次遍歷的方法。loadServiceMethod是一個用來解析API接口中的方法的方法,具體點來講就是上面示例中ApiService中的每一個方法會被解析成一個ServiceMethod對象並進行緩存。

  2. 不管validateEagerly是true仍是false,都會走到return (T) Proxy.newProxyInstance這一步。這裏使用了動態代理返回請求接口類的代理對象,invoke方法中先判斷方法是不是Object類中方法,是就不作修改按照原樣執行。再調用platform.isDefaultMethod判斷是不是默認方法,是就調用platform.invokeDefaultMethod,該方法中拋出異常。最後這一行:

    return loadServiceMethod(method).invoke(args != null ? args : emptyArgs)
    複製代碼

    也是正常解析接口方法走到的。這裏仍是先調用loadServiceMethod方法,而後執行其返回值ServiceMethod的方法。

如今咱們接着上面說的繼續看loadServiceMethod方法:

// Retrofit類:
    ServiceMethod<?> loadServiceMethod(Method method) {
        // 咱們在【retrofit的成員屬性】中說過serviceMethodCache,主要用於緩存ServiceMethod,
        // 而ServiceMethod,是將Method方法中全部的註解,解析後的對象就是ServiceMethod
        ServiceMethod<?> result = serviceMethodCache.get(method);
        // 從緩存中查找ServiceMethod,有則直接返回
        if (result != null) return result;
        // 若緩存中沒有ServiceMethod,則解析請求接口類中的方法建立ServiceMethod,並緩存
        synchronized (serviceMethodCache) {
            result = serviceMethodCache.get(method);
            if (result == null) {
                // 解析網絡請求接口方法(method)上開發者添加的註釋
                result = ServiceMethod.parseAnnotations(this, method);
                // 以method爲key,緩存ServiceMethod
                serviceMethodCache.put(method, result);
            }
        }
        return result;
    }
複製代碼

loadServiceMethod方法中首先在serviceMethodCache緩存中查找這個方法,若是不爲空直接返回。找不到進入同步代碼塊,同步代碼塊中再次判斷緩存中是否存在該方法,不存在調用ServiceMethod.parseAnnotations方法解析方法註解得到解析結果,並將結果ServiceMethod加入緩存。此方法是雙重鎖定檢查(DCL單例模式)。咱們接着看ServiceMethod的parseAnnotations這個解析註解的方法:

// ServiceMethod類:
    static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
        // 解析註解得到一個RequestFactory(請求工廠,保存有跟請求相關的組件)
        RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
        // 獲取方法返回類型
        Type returnType = method.getGenericReturnType();
        // 返回類型中有變量或者通配符拋出異常
        if (Utils.hasUnresolvableType(returnType)) {
            throw methodError(method,
                    "Method return type must not include a type variable or wildcard: %s",
                    returnType);
        }
        // 返回類型爲空拋出異常
        if (returnType == void.class) {
            throw methodError(method, "Service methods cannot return void.");
        }

        return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
    }
    
// RequestFactory類(請求相關的全部組件,可用來構建OkHttp中的完整請求okhttp3.Request):
    static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
        return new Builder(retrofit, method).build();
    }
    
    private final Method method; // 網絡請求接口中的方法
    private final HttpUrl baseUrl; // 網絡請求基地址
    final String httpMethod; // http請求方法類型,好比:GET、POST等
    private final @Nullable String relativeUrl; // 網絡請求的相對地址,和baseUrl組合即爲絕對地址
    private final @Nullable Headers headers; // 請求頭數據
    private final @Nullable MediaType contentType; // 請求內容類型
    private final boolean hasBody; // 是否有請求體
    private final boolean isFormEncoded; // 表單編碼標識
    private final boolean isMultipart; // 多文件上傳等的標識
    private final ParameterHandler<?>[] parameterHandlers; // 接口方法參數處理程序
    final boolean isKotlinSuspendFunction; // 是否爲kotlin標識
    
    Builder(Retrofit retrofit, Method method) {
        this.retrofit = retrofit;
        this.method = method;
        // 三個數組的初始化
        // 1. 初始化請求接口方法上的註解,對應使用例子中的@GET
        this.methodAnnotations = method.getAnnotations();
        // 2. 初始化請求接口方法參數類型,對應使用例子中的方法參數param的類型String
        this.parameterTypes = method.getGenericParameterTypes();
        // 3. 初始化請求接口方法參數上的註解,對應使用例子中的方法參數param上的@Query
        this.parameterAnnotationsArray = method.getParameterAnnotations();
    }
複製代碼

咱們先來看一下這一部分代碼:

  1. 調用RequestFactory的parseAnnotations方法解析註解得到一個RequestFactory對象
  2. 獲取方法的返回類型並校驗異常狀況
  3. 繼續調用HttpServiceMethod的parseAnnotations方法

咱們從上面代碼中能夠簡單的看出第1步中,parseAnnotations方法以建造者模式建立一個RequestFactory對象,並在其Builder中初始化了三個數組,分別用來保存請求接口方法中的:

1.方法上的註解、2.方法參數的類型、3.方法參數裏的註解
複製代碼

咱們接着看第1步中RequestFactory.Builder.build()方法:

// RequestFactory.Builder類:
    RequestFactory build() {
        // 1. 循環解析方法上的註解
        for (Annotation annotation : methodAnnotations) {
            parseMethodAnnotation(annotation);
        }
        // HTTP請求方法類型爲空拋出異常
        if (httpMethod == null) {
            throw methodError(method, "HTTP method annotation is required (e.g., @GET, @POST, etc" +".).");
        }
        // 註解錯誤拋出異常,Multipart與FormUrlEncoded必須在有請求體的post請求上使用
        if (!hasBody) {
            if (isMultipart) {
                throw methodError(method,
                        "Multipart can only be specified on HTTP methods with request body (e.g.," +" @POST).");
            }
            if (isFormEncoded) {
                throw methodError(method, "FormUrlEncoded can only be specified on HTTP methods " +   "with "+ "request body (e.g., @POST).");
            }
        }
        // 得到方法參數個數
        int parameterCount = parameterAnnotationsArray.length;
        parameterHandlers = new ParameterHandler<?>[parameterCount];
        // 2. 循環遍歷解析每一個請求接口方法的參數
        for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
            // 傳入經過從Builder()構造函數中初始化的parameterTypes和parameterAnnotationsArray對應位置的值
            parameterHandlers[p] =
                    parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p],p == lastParameter);
        }
        // 3. 判斷各類使用錯誤狀況拋出對應異常
        if (relativeUrl == null && !gotUrl) {
            throw methodError(method, "Missing either @%s URL or @Url parameter.", httpMethod);
        }
        if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
            throw methodError(method, "Non-body HTTP method cannot contain @Body.");
        }
        if (isFormEncoded && !gotField) {
            throw methodError(method, "Form-encoded method must contain at least one @Field.");
        }
        if (isMultipart && !gotPart) {
            throw methodError(method, "Multipart method must contain at least one @Part.");
        }
        // 4. 建立RequestFactory對象返回
        return new RequestFactory(this);
    }

    // 1.1 解析方法註解
    private void parseMethodAnnotation(Annotation annotation) {
        // 根據註解類型,解析方法、路徑或者初始化header、isMultipart、isFormEncoded等成員屬性
        if (annotation instanceof DELETE) {
            parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
        } else if (annotation instanceof GET) {
            parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
        } else if (annotation instanceof HEAD) {
            parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
        } else if (annotation instanceof PATCH) {
            parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
        } else if (annotation instanceof POST) {
            parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
        } else if (annotation instanceof PUT) {
            parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
        } else if (annotation instanceof OPTIONS) {
            parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
        } else if (annotation instanceof HTTP) {
            HTTP http = (HTTP) annotation;
            parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
        } else if (annotation instanceof retrofit2.http.Headers) {
            String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
            if (headersToParse.length == 0) {
                throw methodError(method, "@Headers annotation is empty.");
            }
            headers = parseHeaders(headersToParse);
        } else if (annotation instanceof Multipart) {
            if (isFormEncoded) {
                throw methodError(method, "Only one encoding annotation is allowed.");
            }
            isMultipart = true;
        } else if (annotation instanceof FormUrlEncoded) {
            if (isMultipart) {
                throw methodError(method, "Only one encoding annotation is allowed.");
            }
            isFormEncoded = true;
        }
    }
    
    // 1.2 解析Http方法和路徑
    private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
        if (this.httpMethod != null) {
            throw methodError(method, "Only one HTTP method is allowed. Found: %s and %s.",
                    this.httpMethod, httpMethod);
        }
        // 初始化httpMethod和hasBody成員屬性
        this.httpMethod = httpMethod;
        this.hasBody = hasBody;

        if (value.isEmpty()) {
            return;
        }

        // 獲取相對URL路徑和現有查詢字符串(若是存在)。
        int question = value.indexOf('?');
        if (question != -1 && question < value.length() - 1) {
            // 確保查詢字符串沒有任何命名參數。
            String queryParams = value.substring(question + 1);
            Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
            if (queryParamMatcher.find()) {
                throw methodError(method, "URL query string \"%s\" must not have replace block. " + "For dynamic query parameters use @Query.", queryParams);
            }
        }
        // 初始化relativeUrl和relativeUrlParamNames成員屬性
        this.relativeUrl = value;
        this.relativeUrlParamNames = parsePathParameters(value);
    }
    
    // 2.1 解析請求方法中的參數
    private @Nullable ParameterHandler<?> parseParameter(
            int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
        ParameterHandler<?> result = null;
        if (annotations != null) {
            for (Annotation annotation : annotations) {
                // 解析參數中的註解,包括參數中的可能包含的路徑、查詢條件等等
                // 因爲此方法代碼過多,暫就不分析啦,感興趣的小夥伴自行查看吧。
                ParameterHandler<?> annotationAction =
                        parseParameterAnnotation(p, parameterType, annotations, annotation);

                if (annotationAction == null) {
                    continue;
                }

                if (result != null) {
                    throw parameterError(method, p, "Multiple Retrofit annotations found, only one allowed.");
                }

                result = annotationAction;
            }
        }

        if (result == null) {
            if (allowContinuation) {
                try {
                    if (Utils.getRawType(parameterType) == Continuation.class) {
                        isKotlinSuspendFunction = true;
                        return null;
                    }
                } catch (NoClassDefFoundError ignored) {
                }
            }
            throw parameterError(method, p, "No Retrofit annotation found.");
        }

        return result;
    }
複製代碼

build方法中作了四件事:

  1. 經過從Builder()構造函數中初始化的methodAnnotations,解析方法上的註解得到解析Http方法、路徑、請求頭等信息,並初始化部分紅員屬性。
  2. 循環遍歷解析每一個請求接口方法的參數,經過調用parseParameter方法,並傳入經過從Builder()構造函數中初始化的parameterTypes和parameterAnnotationsArray對應位置的值,來解析方法參數以及參數中的註解,最後保存在parameterHandlers數組中。
  3. 判斷各類使用錯誤狀況拋出對應異常。
  4. 建立並返回RequestFactory實例。

接着簡單看下HttpServiceMethod的parseAnnotations方法:

// HttpServiceMethod類:
    static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
            Retrofit retrofit, Method method, RequestFactory requestFactory) {
        boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
        boolean continuationWantsResponse = false;
        boolean continuationBodyNullable = false;
        // 得到方法上的全部註解
        Annotation[] annotations = method.getAnnotations();
        // 1. 獲取方法返回類型
        Type adapterType;
        if (isKotlinSuspendFunction) {
            ... // 本文不分析kotlin部分
        } else {
            // 非Kotlin,獲取方法返回類型,即用於肯定使用哪一個網絡請求適配器
            adapterType = method.getGenericReturnType();
        }
        // 2. 調用createCallAdapter建立一個CallAdapter網絡請求適配器
        CallAdapter<ResponseT, ReturnT> callAdapter =
                createCallAdapter(retrofit, method, adapterType, annotations);
        // 得到CallAdapter的響應類型
        Type responseType = callAdapter.responseType();
        // 是okhttp中的Response拋出異常
        if (responseType == okhttp3.Response.class) {
            throw methodError(method, "'"
                    + getRawType(responseType).getName()
                    + "' is not a valid response body type. Did you mean ResponseBody?");
        }
        // 響應類型不包含泛型類型拋出異常
        if (responseType == Response.class) {
            throw methodError(method, "Response must include generic type (e.g., " +
                    "Response<String>)");
        }
        // TODO support Unit for Kotlin?
        if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
            throw methodError(method, "HEAD method must use Void as response type.");
        }
        // 調用createResponseConverter方法建立ResponseConverter數據轉換器
        Converter<ResponseBody, ResponseT> responseConverter =
                createResponseConverter(retrofit, method, responseType);
        // 獲取請求工廠
        okhttp3.Call.Factory callFactory = retrofit.callFactory;
        if (!isKotlinSuspendFunction) { // 非Kotlin
            // 3. 建立並返回CallAdapted,參數:requestFactory、callFactory、responseConverter、callAdapter
            return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
        } ...
    }

// HttpServiceMethod.CallAdapted類:
    CallAdapted(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
                Converter<ResponseBody, ResponseT> responseConverter,
                CallAdapter<ResponseT, ReturnT> callAdapter) {
        super(requestFactory, callFactory, responseConverter);
        // 初始化網絡適配器
        this.callAdapter = callAdapter;
    }
複製代碼

先來梳理下HttpServiceMethod的parseAnnotations方法的流程:

  1. 首先調用createCallAdapter方法建立一個網絡請求適配器。
  2. 調用createResponseConverter方法建立了響應數據轉換器
  3. 接着從傳入的retrofit對象中獲取到網絡請求工廠callFactory,最後經過以上這幾個對象建立了一個CallAdapted返回。注:CallAdapted爲HttpServiceMethod內部靜態類,而且是HttpServiceMethod的子類,即咱們上面【retrofit的成員屬性】中的serviceMethodCache緩存集合中緩存的ServiceMethod,實際是CallAdapted對象。

下面咱們仍是來深刻分別看一下這幾步具體邏輯:

  • createCallAdapter:
// HttpServiceMethod類:
    private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
            Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
        try {
            // 調用retrofit.callAdapter方法
            return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
        } catch (RuntimeException e) { // Wide exception range because factories are user code.
            throw methodError(method, e, "Unable to create call adapter for %s", returnType);
        }
    }

// Retrofit類:
    public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
        // 能夠看出callAdapter就是一個包裝方法,繼而調用nextCallAdapter
        return nextCallAdapter(null, returnType, annotations);
    }

    public CallAdapter<?, ?> nextCallAdapter(
        @Nullable CallAdapter.Factory skipPast ,Type returnType,Annotation[] annotations) {
        checkNotNull(returnType, "returnType == null");
        checkNotNull(annotations, "annotations == null");
        // 從網絡請求適配器工廠集合中查找傳入的適配器的位置
        // 這裏注意到nextCallAdapter方法傳遞的skipPast參數爲null,因此這裏indexOf返回-1,最終初始start爲0
        int start = callAdapterFactories.indexOf(skipPast) + 1;
        // 循環遍歷網絡請求適配器工廠集合
        for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
            // 調用Factory的get方法,根據網絡請求接口方法的返回值,獲取對應適配器
            CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations,this);
            // 不爲空就返回adapter
            if (adapter != null) {
                return adapter;
            }
        }

        ...
    }
複製代碼

從這段代碼中能夠看清晰的看出其調用順序,nextCallAdapter方法中遍歷網絡請求適配器工廠集合,根據方法的返回類型調用工廠的get得到CallAdapter。還記得建立工廠集合時默認添加了一個DefaultCallAdapterFactory嗎?Retrofit默認方法返回類型Call就對應了這個工廠。進入它的get方法查看一下:

// DefaultCallAdapterFactory類:
    @Override
    public @Nullable CallAdapter<?, ?> get(
            Type returnType, Annotation[] annotations, Retrofit retrofit) {
        if (getRawType(returnType) != Call.class) {
            return null;
        }
        if (!(returnType instanceof ParameterizedType)) {
            throw new IllegalArgumentException(
                    "Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
        }
        final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);

        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) {
                return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
            }
        };
    }
複製代碼

DefaultCallAdapterFactory的get方法中根據傳入的方法返回類型判斷,返回類型不是Call類型就直接返回null。類型正確會返回一個CallAdapter。

  • createResponseConverter:
// HttpServiceMethod類:
    private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
            Retrofit retrofit, Method method, Type responseType) {
        Annotation[] annotations = method.getAnnotations();
        try {
            // 調用Retorfit中的方法responseBodyConverter
            return retrofit.responseBodyConverter(responseType, annotations);
        } catch (RuntimeException e) { // Wide exception range because factories are user code.
            throw methodError(method, e, "Unable to create converter for %s", responseType);
        }
    }

// Retrofit類:
    public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
        // 同callAdapter方法爲包裝方法
        return nextResponseBodyConverter(null, type, annotations);
    }
    
    // 該方法邏輯和nextCallAdapter相似
    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++) {
            // 調用數據轉換器工廠的responseBodyConverter方法,根據responseType類型獲取數據轉化器
            Converter<ResponseBody, ?> converter =
                    converterFactories.get(i).responseBodyConverter(type, annotations, this);
            if (converter != null) {
                //noinspection unchecked
                return (Converter<ResponseBody, T>) converter;
            }
        }

        ...
    }
複製代碼

咱們發現createCallAdapter和createResponseConverter,這兩個方法的流程很相似,都是會調用Retrofit類中對應方法,以後再調用對應next方法遍歷集合,從中得到合適的適配器和轉換器。這裏來看下經常使用的Gson轉換器的responseBodyConverter方法:

// GsonConverterFactory類:
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
                                                            Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        // 返回一個GsonResponseBodyConverter對象
        return new GsonResponseBodyConverter<>(gson, adapter);
    }
複製代碼

終於能夠回到Retrofit的create方法裏了,因爲以前分析可知loadServiceMethod方法最終會得到一個CallAdapted對象,這裏就會接着調用它的invoke方法,而CallAdapted中沒有實現invoke方法,invoke方法在其父類HttpServiceMethod中:

// HttpServiceMethod類:
    @Override
    final @Nullable
    ReturnT invoke(Object[] args) {
        // 建立了一個Call,實現類:OkHttpCall,注意這個Call還不是OkHttp中的Call類,它仍是Retrofit包中的類
        Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory,responseConverter);
        return adapt(call, args);
    }
    
// OkHttpCall類:
    final class OkHttpCall<T> implements Call<T> {
        // 保存網絡請求信息的工廠對象
        private final RequestFactory requestFactory;
        private final Object[] args; // 網絡請求真實參數
        private final okhttp3.Call.Factory callFactory;
        private final Converter<ResponseBody, T> responseConverter; // 數據轉換器

        private volatile boolean canceled; // 判斷是否取消call
        @GuardedBy("this")
        private @Nullable okhttp3.Call rawCall; // 這個rawCall纔是OkHttp中的Call
        @GuardedBy("this")
        private boolean executed; // 異步請求時使用的標誌位
        
        ......
    }
    
// HttpServiceMethod.CallAdapted類:
    @Override
    protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
        return callAdapter.adapt(call);
    }
複製代碼

總結一下此處的邏輯:

  1. invoke方法中建立了一個Call,此Call實現類爲OkHttpCall(Retrofit包中的類,主要用來包裝OkHttp中真實的Call,即OkHttpCall中的rawCall)。
  2. 而後調用adapt方法將第1步建立的call傳入
  3. 調用以前【createCallAdapter】獲取到的網絡適配器的adapt方法,傳入call,並返回相應的網絡適配器adapt(適配)後的Call。好比:默認的CallAdapter返回的ExecutorCallbackCall、RxJava2CallAdapter返回的CallEnqueueObservable或者CallExecuteObservable。

咱們上面【createCallAdapter】使用的是DefaultCallAdapterFactory爲例,介紹的適配器的get方法,那麼咱們如今也使用DefaultCallAdapterFactory返回的CallAdapter爲例,來介紹一下adapt方法:

@Override
    public @Nullable CallAdapter<?, ?> get(
            Type returnType, Annotation[] annotations, Retrofit retrofit) {
        ...
        
        return new CallAdapter<Object, Call<?>>() {
            @Override
            public Type responseType() {
                return responseType;
            }

            @Override
            public Call<Object> adapt(Call<Object> call) {
                return executor == null
                        ? call
                        : new ExecutorCallbackCall<>(executor, call);
            }
        };
    }
複製代碼

return 返回了CallAdapter,其中adapt方法返回的是一個ExecutorCallbackCall類型,它實現了Retrofit的Call接口,就是最終返回的適配後的Call類型。

總結一下:

  • Call:
    1. OkHttpCall是Retrofit對OkHttp中的Call的包裝
    2. 不一樣的網絡適配器會再次將OkHttpCall進行不一樣的適配,並生成適合於不一樣適配器的Call
  • CallAdapter以及CallAdapter.Factory
    1. 全部網絡適配器都須要實現CallAdapter方法:
      • responseType 返回此適配器在將HTTP響應主體轉換爲Java 對象時使用的值類型。例如,{@code Call}的響應類型是{@code User}
      • adapt 返回此適配器適合的Call的包裝類T(即泛型類,包裝OkHttpCall而生成)
    2. 全部網絡適配器工廠都須要繼承於CallAdapter.Factory
      • get 返回網絡請求接口返回值類型的調用適配器,若此工廠沒法處理,則返回null。
      • getParameterUpperBound 從{@code type}中提取{@code index}處的泛型參數的上限,好比:Map<String, ? extends Runnable>} 返回 Runnable
      • getRawType 從返回值類型中提取原始類類型。好比:Observable<List> 返回 List

Retrofit同步請求execute方法

Retrofit中的同步異步請求實際上很相似,只是異步請求最後會把回調方法交給【retrofit的Builder】中提到的回調執行器,來切換爲主線程並處理回調。Retrofit中同步不管是哪一種網絡請求適配器,最後調用的都是OkHttpCall的execute()方法,例如:默認網絡請求適配器工廠建立的適配器 adapt 適配後返回的ExecutorCallbackCall類:

// DefaultCallAdapterFactory.ExecutorCallbackCall類:
    final Executor callbackExecutor; // 回調執行器
    final Call<T> delegate; // 實際上爲OkHttpCall

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

    @Override
    public Response<T> execute() throws IOException {
        return delegate.execute(); // 執行OkHttpCall的execute()方法
    }
複製代碼

從上面代碼能夠很明顯看出,Retrofit同步請求最後調用的仍是OkHttpCall的execute()方法:

// OkHttpCall類:
    @Override
    public Response<T> execute() throws IOException {
        okhttp3.Call call;

        synchronized (this) {
            if (executed) throw new IllegalStateException("Already executed.");
            executed = true; // 防止重複執行

            ...

            call = rawCall;
            if (call == null) {
                try {
                    call = rawCall = createRawCall(); // 建立真實Call
                } catch (IOException | RuntimeException | Error e) {
                    throwIfFatal(e); //  Do not assign a fatal error to creationFailure.
                    creationFailure = e;
                    throw e;
                }
            }
        }

        if (canceled) {
            call.cancel();
        }
        // 執行同步請求,並阻塞等待解析響應
        return parseResponse(call.execute());
    }
    
    // 建立真實Okhttp Call
    private okhttp3.Call createRawCall() throws IOException {
        // callFactory實際上爲:OkHttpClient(【retrofit的Builder】處有說明)
        // requestFactory請求工廠構建OkHttp中的Request(【Retrofit.create(經過動態代理生成請求對象)】有說明)
        okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
        if (call == null) {
            throw new NullPointerException("Call.Factory returned null.");
        }
        return call;
    }
複製代碼

execute方法中首先判斷當前call是否爲空,爲空則調用createRawCall方法建立一個Call,這個對象類型能夠看到就是OkHttp中的Call類型,接着調用call.execute方法得到OkHttp返回的Response,最後再調用parseResponse方法解析響應結果返回。

// OkHttpCall類:
    Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
        // 得到響應中的body
        ResponseBody rawBody = rawResponse.body();

        // 移除rawResponse中的body只包含狀態(至關於空響應)
        rawResponse = rawResponse.newBuilder()
                .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
                .build();
        // 得到響應中的響應碼
        int code = rawResponse.code();
        // 響應碼小於200大於300表示錯誤
        if (code < 200 || code >= 300) {
            try {
                // Buffer the entire body to avoid future I/O.
                ResponseBody bufferedBody = Utils.buffer(rawBody);
                // 調用Response.error將body和rawResponse返回
                return Response.error(bufferedBody, rawResponse);
            } finally {
                rawBody.close();
            }
        }
        // 響應碼爲204或者205
        if (code == 204 || code == 205) {
            rawBody.close();
            // 響應碼爲204或者205調用Response.success返回響應體爲空
            return Response.success(null, rawResponse);
        }
        // 將響應體body封裝成一個ExceptionCatchingResponseBody對象
        ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
        try {
            // 調用responseConverter.convert方法轉換響應結果(實際上就是gson解析數據)
            T body = responseConverter.convert(catchingBody);
            // 調用Response.success將轉換好的body和rawResponse返回
            return Response.success(body, rawResponse);
        } catch (RuntimeException e) {
            // 若是底層源引起異常,則傳播該異常,而不是指示它是運行時異常。
            catchingBody.throwIfCaught();
            throw e;
        }
    }

// 數據轉化器,轉換響應結果
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
    private final Gson gson;
    private final TypeAdapter<T> adapter;

    GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
        this.gson = gson;
        this.adapter = adapter;
    }

    @Override
    public T convert(ResponseBody value) throws IOException {
        JsonReader jsonReader = gson.newJsonReader(value.charStream());
        try {
            T result = adapter.read(jsonReader);
            if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
                throw new JsonIOException("JSON document was not fully consumed.");
            }
            return result;
        } finally {
            value.close();
        }
    }
}
複製代碼

parseResponse方法中:

  1. 首先將響應體和響應狀態信息分離,響應體單獨拿了出來進行解析。
  2. 而後判斷響應碼不在200到300之間及異常狀況直接調用Response.error(bufferedBody, rawResponse)返回一個Retrofit中的Response.
  3. 返回碼爲204或者205表示響應成功可是沒有響應體返回,因此調用Response.success傳入的響應體爲null。
  4. 最後其餘正常狀況就調用數據轉換器responseConverter的convert方法轉換響應,轉換後的結果經過Response.success(body, rawResponse)返回Retrofit中完整的響應結果。

Retrofit中的Response和OkHttpCall相似,都不是OkHttp中的,而至關於OkHttp中okhttp3.Response和okhttp3.Call的包裝類,而Retrofit中的Response中的success和error實際上就是返回不一樣狀態的Response。

GsonResponseBodyConverter的convert方法實現就比較簡單了,就是調用Gson中的方法了。經過構造中傳入的Gson對象建立一個JsonReader並將響應體的字符流傳入,最後調用TypeAdapter.read(jsonReader)將請求體解析獲得對應實體類。

Retrofit異步請求enqueue方法

【Retrofit同步請求execute方法】裏已經說了,同步異步請求實際上很相似,那麼咱們來看一下OkHttpCall的enqueue方法:

// OkHttpCall類:
    @Override
    public void enqueue(final Callback<T> callback) {
        checkNotNull(callback, "callback == null");

        okhttp3.Call call;
        Throwable failure;

        synchronized (this) {
            if (executed) throw new IllegalStateException("Already executed.");
            executed = true;

            call = rawCall;
            failure = creationFailure;
            if (call == null && failure == null) {
                try {
                    // 建立OkHttp中的Call,同 同步請求
                    call = rawCall = createRawCall();
                } catch (Throwable t) {
                    throwIfFatal(t);
                    failure = creationFailure = t;
                }
            }
        }

        if (failure != null) {
            callback.onFailure(this, failure);
            return;
        }
        // 判斷請求是否取消
        if (canceled) {
            call.cancel();
        }
        // 調用OkHttp中的call.enqueue
        call.enqueue(new okhttp3.Callback() {
            @Override // 響應成功
            public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
                Response<T> response;
                try {
                    // 返回成功解析Response(同 同步請求)
                    response = parseResponse(rawResponse);
                } catch (Throwable e) {
                    throwIfFatal(e);
                    callFailure(e);
                    return;
                }

                try {
                    // 調用callback.onResponse(成功回調)
                    callback.onResponse(OkHttpCall.this, response);
                } catch (Throwable t) {
                    throwIfFatal(t);
                    t.printStackTrace(); // TODO this is not great
                }
            }

            @Override // 響應失敗
            public void onFailure(okhttp3.Call call, IOException e) {
                // 處理失敗
                callFailure(e);
            }

            private void callFailure(Throwable e) {
                try {
                    // 調用callback.onFailure(失敗回調)
                    callback.onFailure(OkHttpCall.this, e);
                } catch (Throwable t) {
                    throwIfFatal(t);
                    t.printStackTrace(); // TODO this is not great
                }
            }
        });
    }
複製代碼

OkHttpCall中的enqueue方法的邏輯和同步方法的邏輯相似,一樣仍是先建立OkHttp中的Call,再調用OkHttp中Call的enqueue方法,成功得到到OkHttp的返回結果後再一樣經過parseResponse方法解析,解析以後回調callback.onResponse,若OkHttp返回失敗則回調callback.onFailure。而在默認的網絡請求適配器中會將請求的響應回調發送到主線程中:

// DefaultCallAdapterFactory.ExecutorCallbackCall類:
    @Override
    public void enqueue(final Callback<T> callback) {
        checkNotNull(callback, "callback == null");

        delegate.enqueue(new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, final Response<T> response) {
                // 回調執行器,【retrofit的Builder】說明,實際上爲MainThreadExecutor
                // 而MainThreadExecutor裏包含一個在主線程的Handler
                // 而MainThreadExecutor中的execute方法中,實際上調用了Handler的post方法將傳入的Runnable發回主線程
                callbackExecutor.execute(new Runnable() {
                    @Override
                    public void run() {
                        if (delegate.isCanceled()) {
                            callback.onFailure(ExecutorCallbackCall.this, new IOException(
                                    "Canceled"));
                        } else {
                            callback.onResponse(ExecutorCallbackCall.this, response);
                        }
                    }
                });
            }

            @Override
            public void onFailure(Call<T> call, final Throwable t) {
                // 同上
                callbackExecutor.execute(new Runnable() {
                    @Override
                    public void run() {
                        callback.onFailure(ExecutorCallbackCall.this, t);
                    }
                });
            }
        });
    }
複製代碼

經過默認的網絡請求適配器能夠看出,不一樣適配器對最終的響應有不一樣的處理。

Retrofit中的設計模式

  • 外觀(門面)模式:Retrofit
  • 建造者模式:Retrofit、RequestFactory
  • 動態代理模式:Retrofit.create
  • 裝飾模式:ExecutorCallbackCall(有人說此類是靜態代理模式,我的看法更認爲是裝飾模式)
  • 適配器模式:CallAdapter
  • 工廠模式:CallAdapter.Factory(工廠方法模式)、Converter.Converter(工廠方法模式)、Platform(簡單、靜態工廠)

思考:

  1. 靜態代理模式和裝飾模式的區別?
  2. 適配器模式與裝飾模式的區別? 裝飾與適配器都有一個別名叫作包裝模式(Wrapper),它們看似都是起到包裝一個類或對象的做用,可是使用它們的目的很不一同樣。適配器模式的意義是要將一個接口轉變成另外一個接口,它的目的是經過改變接口來達到重複使用的目的。 而裝飾模式不是要改變被裝飾對象的接口,而是偏偏要保持原有的接口,可是加強原有對象的功能,或者改變原有對象的處理方式而提高性能。
代理模式:爲其餘對象提供一種代理以控制對這個對象的訪問。在某些狀況下,一個對象不適合或者不能直接引用另外一個對象,而代理對象能夠在客戶端和目標對象之間起到中介的做用。
	抽象角色:經過接口或抽象類聲明真實角色實現的業務方法。
	代理角色:實現抽象角色,是真實角色的代理,經過真實角色的業務邏輯方法來實現抽象方法,並能夠附加本身的操做。
	真實角色:實現抽象角色,定義真實角色所要實現的業務邏輯,供代理角色調用。
	注:代理模式職責清晰,真實的角色就是實現實際的業務邏輯,不用關心其餘非本職責的事務,經過後期的代理完成一件完成事務,附帶的結果就是編程簡潔清晰。
適配器模式:將一個類的接口適配成用戶所期待的。一個適配容許一般由於接口不兼容而不能在一塊兒工做的類工做在一塊兒,作法是將類本身的接口包裹在一個已存在的類中。
	類適配器:
		public class Adaptee { // 源角色
			public void SpecificRequest(){
				System.out.println("須要適配的接口方法");
			}
		}
		public interface Target { // 目標角色
			void Request(); // 期待獲得的接口
		}
		public class Adapter extends Adaptee implements Target { // 適配器角色
			@Override
			public void Request() {
				SpecificRequest(); // 源角色須要適配的方法
				System.out.println("被適配後的方法");
			}


			public static void main(String[] args) {
				Target target = new Adapter();
				target.Request();

			}
		}
	對象適配器:
		public class Adapter  implements  Target{
			//經過組合的方式實現注入
			private Adaptee adaptee; // 1
		//	private Adaptee adaptee = new Adaptee(); // 2

			public Adapter(Adaptee adaptee){
				this.adaptee=adaptee;
			}


			@Override
			public void Request() {
				adaptee.SpecificRequest();
				System.out.println("被適配後的方法");
			}
		}

裝飾模式:沒必要改變原類文件和使用繼承的狀況下,動態地擴展一個對象的功能(使得它比原來更「漂亮」,或者在功能上更強大)。它是經過建立一個包裝對象,也就是裝飾來包裹真實的對象。(java IO 流是典型的裝飾模式。)
	即做爲原來的這個類的使用者還不該該感覺到裝飾前與裝飾後有什麼不一樣,即用法不變,不然就破壞了原有類的結構了,因此裝飾器模式要作到對被裝飾類的使用者透明,這是對裝飾器模式的一個基本要求。
複製代碼

代理模式詳情可參考本人第一篇文章:Binder機制之AIDL

OkHttp的源碼分析,可參考上一篇:主流開源框架之OkHttp3深刻了解

參考連接:

juejin.im/post/5d458a…

www.jianshu.com/p/abd144912…

www.jianshu.com/p/fb8d21978…

...

(注:如有什麼地方闡述有誤,敬請指正。)

相關文章
相關標籤/搜索