Android每週一輪子:Retrofit

前言

充足的時間纔是第一輩子產力。當源碼看多了以後,對於不少點的梳理上可能就不會像以前那樣更具體了,本篇主要仍是在於對實現主流程的分析。Retrofit在以前項目中並無用到過,此次決定來看一些Retrofit相關實現來了解其中的原理。對於想要了解Java中的動態代理應用,想要用更簡潔的方式實現網絡請求,Retrofit多是最好的學習案例了,以前的項目中在寫網絡請求的時候,每次都須要寫大量的樣板代碼來構造出一個網絡請求,代碼一旦增長,犯錯誤的機率也就會增長,維護成本也就增長,同時也下降了開發效率,工程化最佳實踐的目標是讓開發者只專一於本身的業務邏輯,而不須要關心下層具體的實現,儘量暴露少的業務無關的內容給到上層。git

基礎使用

對於Retrofit須要定義一個接口類,聲明要請求的接口和其中參數的傳遞方式,而後經過調用create方法就能夠構造一個Service類,調用相應的方法便可幫助咱們進行網絡請求的發送,代碼很是簡潔,同時咱們也能夠經過對不一樣的業務模塊分Service的方式來實現對於不一樣業務接口的隔離。github

public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}

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

GitHubService service = retrofit.create(GitHubService.class);

源碼分析

Retrofit實例的建立是主要是進行一些信息的配置,這裏核心分析的在於其create方法,本篇文章的分析將會順着create方法的實現到其最終一個網絡請求的調用,同時結合着對Retrofit源碼的分析來進一步展開對於Java中動態代理實現的分析。api

public <T> T create(final Class<T> service) {
    validateServiceInterface(service);
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
        private final Platform platform = Platform.get();
        private final Object[] emptyArgs = new Object[0];
        //對於代理中的繼承自Object的方法還有平臺方法直接invoke執行
        @Override public @Nullable 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);
        }
        //對於其它咱們定義的方式調用loadServiceMethod
        return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
      }
    });
}

在Retrofit的實現中create是一個很關鍵的方法,也是咱們做爲源碼分析的一個切入點。首先看其第一個方法validateServiceInterface,該方法主要對傳遞的Service類進行校驗,同時經過對註解的處理來獲取到其中定義方法的相關信息。具體核心實現以下。緩存

for (Method method : service.getDeclaredMethods()) {
    if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
        loadServiceMethod(method);
    }
}

對於service中定義的方法進行遍歷,而後經過調用loadServcieMethod進行相應的處理網絡

ServiceMethod<?> loadServiceMethod(Method method) {
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
    result = serviceMethodCache.get(method);
    if (result == null) {
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
    }
    }
    return result;
}

loadServiceMethod方法是Retrofit的整個框架的實現的一個很核心的點了,首先會從ServiceMethodCache中進行相應的查找,若是查找到則直接返回,沒有的話則會調用ServiceMethod的註解處理方法,parseAnnotaion來生成一個ServiceMethod,同時將其加入到緩存之中。那麼接下來,咱們來看一下ServiceMethod的相關實現,和其註解解析方法。框架

static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    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的parseAnnoations和HttpServiceMethod的parseAnnotations方法。接下咱們RequestFactory只是經過retorift和method構建了一個RequestFactory,記錄了方法的參數,返回值類型還有註解信息。最後將其做爲參數傳遞至HttpServiceMethod中的parseAnnotations,對於註解的處理主要是來將咱們在發送網絡請求時須要的信息從註解中解析出來,當調用invoke方法的時候,結合解析出來的參數構建一個網絡請求。ide

final ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
}

在動態代理中當咱們進行一個方法調用的時候實際執行代碼以下源碼分析

loadServiceMethod(method).invoke(args != null ? args : emptyArgs);

對於loadServiceMethod方法,咱們以前已經分析過,這裏主要根據方法解析的緩存中查找,而後調用其invoke方法,來構造一個OkHttp的請求。而後調用okhttp的相應的請求方法。學習

總結

對於Rerofit在項目中的使用,最上層是咱們的業務邏輯,下面是咱們針對每個業務邏輯模塊定義的API,第三層是Retrofit對於API層向網絡請求OKhttp層的橋接,最終經過OkHttp將請求發送出去。同時其藉助於註解與動態代理讓代碼的實現變的更優雅。藉助於接口的形式來很好的實現網絡請求在業務層的隔離。註解與動態代理搭配的形式對於後續的開發設計也是頗有啓發意義的。ui

相關文章
相關標籤/搜索