Retrofit2原始碼解析(一)

xxq2dream發表於2018-09-13

本文基於Retrofit2的2.4.0版本

implementation `com.squareup.retrofit2:retrofit:2.4.0`

Retrofit2底層基於OkHttp3,是對利用OkHttp3請求網路的一種封裝,可以使我們避免寫很多重複的呼叫網路請求的程式碼,同時靈活性很高,可以定製自定義的OkHttpClient、自定義的資料解析轉換器(比如Gson、Jackson等)、自定義的請求轉換器(比如結合RxJava)。

Retrofit2的另一個特點就是使用執行時註解,我們在使用時可以根據需要來利用註解將我們的業務呼叫介面轉換成Http請求的介面。

下面先來看看我們使用Retrofit2發起網路請求的步驟

(1)建立我們的具體業務介面,這裡比如我們呼叫淘寶的IP地址庫

public interface MyService {
    @GET("getIpInfo.php=11.11.11.11")
    Call<IpBean> getData();
}

(2)建立Retrofit

retrofit = new Retrofit.Builder()
    .baseUrl("https://ip.taobao.com/service/")
    .addConverterFactory(GsonConverterFactory.create())
    .build();

可見Retrofit2採用的是Builder模式來構建的

(3)利用Retrofit建立我們的介面物件,生成Call物件,並呼叫請求網路方法

MyService myService = retrofit.create(MyService.class);
Call<IpBean> call = myService.getData();
call.enqueue(new Callback<IpBean>() {
    @Override
    public void onResponse(Call<IpBean> call, Response<IpBean> response) {
        
    }

    @Override
    public void onFailure(Call<IpBean> call, Throwable t) {
        
    }
});

Retrofit的建立

首先我們看看建立Retrofit時都做了哪些工作

public Retrofit build() {
    //這裡可以看出我們必需設定baseUrl
    if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
    }
    
    //如果我們沒有設定自定義的OkHttpClient,就用預設的OkHttpClient
    okhttp3.Call.Factory callFactory = this.callFactory;
    if (callFactory == null) {
        callFactory = new OkHttpClient();
    }
    
    //這個callbackExecutor用於回撥到UI執行緒
    Executor callbackExecutor = this.callbackExecutor;
    if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
    }

    //將我們設定的Call介面卡新增到列表中,比如RxJava的介面卡
    List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
    //新增預設的Call介面卡
    callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

    // Make a defensive copy of the converters.
    List<Converter.Factory> converterFactories =
            new ArrayList<>(1 + this.converterFactories.size());

    //新增資料轉換器,用於將網路請求返回的結果轉換成我們需要的型別
    converterFactories.add(new BuiltInConverters());
    converterFactories.addAll(this.converterFactories);
    
    //構建Retrofit
    return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
            unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}

通過上面Retrofit2的Builder的build方法,我們可以看出在Retrofit2中主要有這麼幾個部分:

(1)用於執行具體網路請求的callFactory,也就是OkHttpClient。所以說Retrofit2是基於OkHttp3的封裝。

(2)callbackExecutor回撥執行器,這個是用於網路請求返回後回撥到主執行緒的。我們知道,在利用OkHttp3進行網路請求時,我們需要手動回撥到主執行緒,以便更新UI。那我們來看看這個預設的defaultCallbackExecutor是不是這樣。

//Retrofit.class
public Builder() {
    this(Platform.get());
}

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

可以看到在Builder中呼叫的是Platform的get方法,返回對應的平臺,然後在build方法裡通過platform的defaultCallbackExecutor得到我們的回撥器。下面我們看看這個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 {
        @Override
        public Executor defaultCallbackExecutor() {
            return new MainThreadExecutor();
        }

        @Override
        CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
            if (callbackExecutor == null) throw new AssertionError();
            return new ExecutorCallAdapterFactory(callbackExecutor);
        }

        static class MainThreadExecutor implements Executor {
            private final Handler handler = new Handler(Looper.getMainLooper());

            @Override
            public void execute(Runnable r) {
                handler.post(r);
            }
        }
    }
}

從上面的原始碼中我們可以看到Platform中會根據當前執行的平臺返回不同的子類,這裡當然就是Android這個內部類了。所以當我們呼叫platform的defaultCallbackExecutor時,實際上呼叫的是Android這個類的defaultCallbackExecutor方法,而這個方法返回的是MainThreadExecutor,它的作用就是利用handler將執行結果回撥到主執行緒中。

(3)callAdapterFactories介面卡列表,這裡面存放的是所有的Call介面卡CallAdapter。這個CallAdapter是幹嘛的呢?我們知道Retrofit2底層是用Okhttp3來請求網路的,那勢必是通過OkHttp3的Call來執行請求,但是我們在實際使用Retrofit2時,可能需要結合請他的三方庫,常見的比如RxJava,那我們介面中所需要返回的可能就是Observable而不是Call了。

@GET("getIpInfo.php?ip=11.11.11.11")
Observable<IpBean> getObservableData();

所以Retrofit2就需要一個Call介面卡CallAdapter,來將Call轉換為我們需要的Observable,這就是CallAdapter的作用。

(4)converterFactories返回結果轉換器列表,這裡面存放的是將網路返回結果,也就是OkHttp3返回的Response,解析轉換成我們需要的實際型別,比如IpBean實體類。如GsonConverterFactory就是一個常用的轉換器,相當於Retrofit2把我們直接使用Okhttp3來請求網路資料時需要將返回結果進行Gson解析的動作也替我們做了。

總結

(1)這裡我們簡單分析了Retrofit的建立過程,可以發現Retrofit中核心部分包括OkHttpClient、Call介面卡、Response轉換器以及用於將請求回撥到UI執行緒的回撥執行器等。

(2)Retrofit的建立採用的是Builder模式,定製化程度很高,我們可以設定自己的OkHttpClient,也可以實現自定義的Call介面卡和Response轉換器,以及請求的回撥執行器。

(3)可見Retrofit雖然做了很大程度的封裝,但是靈活性擴充套件性依然很高,我們幾乎可以擴充套件更改網路請求的大部分過程。

今天我們先淺嘗則止,後面我們再來具體分析下Retrofit2的網路呼叫過程,看看Retrofit2是怎麼利用介面卡模式來為我們提供強大的靈活性的,敬請期待。


歡迎關注我的微信公眾號,和我一起每天進步一點點!
AntDream

相關文章