帶你一塊兒探究Retrofit 源碼,讓你再也不畏懼Retrofit的面試提問

Retrofit,OkHttp,Okio Square 安卓平臺網絡層三板斧源碼學習javascript

基於 retrofit 2.4.0-SNAPSHOT 版本 retrofit github 地址 :java

https://github.com/square/retrofit
複製代碼

Retrofit 是 Square 安卓平臺網絡層三板斧最後一個項目,Retrofit 依賴 OkHttp 。Retrofit 讓 http 網絡請求更加清晰。git

使用方式

1、聲明一個接口,並用接口描述 request
public interface GitHubService {
     @GET("users/{user}/repos")
     Call<List<Repo>> listRepos(@Path("user") String user);
 }
複製代碼
2、方法上面的註釋表示 request 的接口名 ,方法的返回類型就是 http 請求的返回值,方法的參數就是 http 的請求參數。

建立一個 Retrofit 客戶端github

Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("https://api.github.com/")
 .build();

 GitHubService service = retrofit.create(GitHubService.class);
 
複製代碼

Retrofit 建立的時候指定了 request 的接口地址,而後調用 retrofit.create 方法建立一個 GitHubService 實例。api

3、發起網絡請求
Call<List<Repo>> repos = service.listRepos("octocat");
 repos.execute().body()
複製代碼

上面的例子能夠看到,retrofit.create() 方法會建立一個 GitHubService 實例,可是 GitHubService 自己是一個接口。爲了瞭解 retrofit.create() 方法,咱們先看下 Retrofit 的建立過程。數組

Retrofit 建立 Service 實例

建立 Retrofit 對象。

Retrofit 和 OkHttp 同樣都是使用構建者模式建立對象。先看下 Retrofit.Builder 的 build() 方法。緩存

public Retrofit build() {
        if (baseUrl == null) {
            throw new IllegalStateException("Base URL required.");
        }

        okhttp3.Call.Factory callFactory = this.callFactory;
        if (callFactory == null) {
            callFactory = new OkHttpClient();
        }

        Executor callbackExecutor = this.callbackExecutor;
        if (callbackExecutor == null) {
            callbackExecutor = platform.defaultCallbackExecutor();
        }

        // Make a defensive copy of the adapters and add the default Call adapter.
        List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
        adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

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

        return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
                callbackExecutor, validateEagerly);
    }
複製代碼
建立 Retrofit 的時候須要傳遞一下幾個參數
  • callFactory 用來建立一個實現了 okhttp3.Call.Factory 的對象,若是沒有設置,默認爲 OkHttpClient。服務器

  • baseUrl 網絡接口的地址。 -converterFactories 用來把服務器返回的數據轉換爲對象。微信

  • adapterFactories 用來發起網絡請求。網絡

  • callbackExecutor 是一個調度器,用來接收返回的數據,在 Android 上默認是封裝了 handler 的 MainThreadExecutor

  • validateEagerly 是一個開關,若是爲 true 會緩存建立的 ServiceMethod 。

咱們再來看一下retrofit.create()源碼
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, @Nullable 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);
                   }
                   if (platform.isDefaultMethod(method)) {
                       return platform.invokeDefaultMethod(method, service, proxy, args);
                   }
                   ServiceMethod<Object, Object> serviceMethod =
                           (ServiceMethod<Object, Object>) loadServiceMethod(method);
                   OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
                   return serviceMethod.callAdapter.adapt(okHttpCall);
               }
           });
}

複製代碼

這裏用到了一個公共技術點之 Java 動態代理,create 方法傳入一個 Class ,這個 Class 對象就是上文的 GitHubService 的 Class 。

GitHubService 的方法是由 InvocationHandler 代理實現的,重點看三行代碼

......

ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);

OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);

複製代碼
第一行 loadServiceMethod(method)
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;
}
複製代碼

這裏建立了一個 ServiceMethod 對象。

第二行 new OkHttpCall<>(serviceMethod, args)
OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
}
複製代碼

建立了一個 OkHttpCall ,serviceMethod 和 args 是 OkHttpCall 的成員函數。

因此,

第三行 serviceMethod.callAdapter.adapt(okHttpCall)

這裏須要明白 serviceMethod.callAdapter 是怎麼來的

1. 在 ServiceMethod.Builder.build() 中調用 createCallAdapter()
2. 在 createCallAdapter() 中會找到 
   (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations)
3. 在 callAdapter() 中調用 nextCallAdapter
4. nextCallAdapter 會遍歷 adapterFactories 返回一個 CallAdapter。
複製代碼

這裏再回頭看下 adapterFactories Retrofit.Builder.build() 方法中

List<CallAdapter.Factory> adapterFactories = 
    new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
複製代碼

而在 Retrofit.nextCallAdapter() 中

int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
   CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
    if (adapter != null) {
        return adapter;
    }
}
複製代碼

若是沒有設置 AdapterFactory 將會使用一個默認的 AdapterFactory

CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    if (callbackExecutor != null) {
        return new ExecutorCallAdapterFactory(callbackExecutor);
    }
    return DefaultCallAdapterFactory.INSTANCE;
}
複製代碼

因此若是咱們設置了一個 RxJavaCallAdapterFactory,就會返回 RxJavaCallAdapterFactory。

整個建立Retrofit的過程流程爲:

整個建立Retrofit的過程流程圖

發起網絡請求

經過 retrofit.create() 咱們能夠知道,retrofit.create() 返回的是一個代理對象InvocationHandler ,那麼在執行

Call<List> repos = service.listRepos("octocat"); 方法時,調用的其實是 callAdapter.adapt(okHttpCall),以 DefaultCallAdapterFactory 爲例

@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
        return null;
    }

    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Object, Call<?>>() {
        @Override
        public Type responseType() {
            return responseType;
        }

        @Override
        public Call<Object> adapt(Call<Object> call) {
            return call;
        }
    };
}
複製代碼

結合 retrofit.create() 方法能夠得知這裏返回的是一個 OkHttpCall 對象。

接下來使用 OkHttpCall.execute() 或者異步執行 enqueue(Callback callback)

這兩種方式都會調用 createRawCall() 建立一個 okhttp3.Call

private okhttp3.Call createRawCall() throws IOException {
    Request request = serviceMethod.toRequest(args);
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);
    if (call == null) {
        throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
}
複製代碼

此處的 serviceMethod.callFactory 就是 retrofit.create() 中建立的 OkHttpClient() 後面的內容都是由 Okhttp 模塊接管,進行網絡請求,參考okHttp 框架源碼學習

而後調用 parseResponse(call.execute())

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();

    ……
    省略一些 http 返回值處理邏輯
    ……
    try {
        T body = serviceMethod.toResponse(catchingBody);
        return Response.success(body, rawResponse);
    } ……
}
複製代碼

okHttp 請求網絡的返回數據,會交給 serviceMethod.toResponse

R toResponse(ResponseBody body) throws IOException {
    return responseConverter.convert(body);
}
複製代碼

在 ServiceMethod.Builder.build() 方法中能夠找到 responseConverter 是經過 createResponseConverter() 方法的返回對象。

createResponseConverter() 只是報包裹了 retrofit.responseBodyConverter(responseType, annotations) 方法。

retrofit.responseBodyConverter() 繼續跟蹤下去會得知,返回的是 converterFactories 數組的第 0 個對象,也就是內置的 BuiltInConverters.responseBodyConverter() 方法返回的 BufferingResponseBodyConverter

static final class BufferingResponseBodyConverter implements Converter<ResponseBody, ResponseBody> {
    static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter();

    @Override
    public ResponseBody convert(ResponseBody value) throws IOException {
        try {
            // Buffer the entire body to avoid future I/O.
            return Utils.buffer(value);
        } finally {
            value.close();
        }
    }
}
複製代碼

再看一下 Utils.buffer(value)

static ResponseBody buffer(final ResponseBody body) throws IOException {
    Buffer buffer = new Buffer();
    body.source().readAll(buffer);
    return ResponseBody.create(body.contentType(), body.contentLength(), buffer);
}
複製代碼

最終會返回一個從新封裝的 Okhttp 框架的 ResponseBody 對象,過程以下:

https://user-gold-cdn.xitu.io/2017/12/11/16044796288612a4?w=984&h=698&f=jpeg&s=83029

最後來個總結

  • 第一步建立一個Retrofit對象

  • 經過 Retrofit.onCreate()方法把咱們所定義的接口轉化爲接口實例並使用接口中的方法

  • 最終的實例都會調用okHttp的call,retrofit用於OKhttp的,比較靈活

相信本身,沒有作不到的,只有想不到的

若是你以爲此文對您有所幫助,歡迎入羣 QQ交流羣 :232203809 微信公衆號:終端研發部

技術+職場
相關文章
相關標籤/搜索