Retrofit源碼解析

Retrofit源碼結構

Retrofit: 通過註解,把一個Java接口轉化成一個http 請求,底層網絡請求基於okhttp

從Retrofit源碼結構可以看出,Retrofit 源碼分成兩部分
這裏寫圖片描述

一部分是包retrofit2.http裏面的,在Java接口方法中使用,用來控制http行爲的註解。

一部分是retrofit2裏面的,負責把REST API轉化成Java接口。

Retrofit和okhttp的關係

retrofit依賴okhttp庫,retrofit 所有的網絡請求都是由okhttp處理,可以說retrofit是對okhttp封裝了,讓其使用更加簡單方便。
okhttp 準確來說是一個Java庫,沒有Android中主線程和工作線程的概念,Android有兩個限制,第一不能再主線程中直接請求網絡,第二不能在工作線程中直接更新UI,所以,如果我們在Android中直接使用okhttp,需要用到Handler來傳遞請求結果。而如果使用retrofit,則不需要我們去創建線程執行網絡請求,也不需要使用Handler把請求結果從工作線程傳遞到主線程。retrofit直接在主線程中發起異步請求,最後收到請求結果也是在主線程中,非常方便。

主要類和方法

Retrofit:retrofit框架的入口類,主要有兩個功能:
1、通過內部類Builder配置構建Retrofit實例。Builder主要配置選項:

1. client(OkHttpClient client) :設置一個配置好的OkHttpClient實例,不配置的話retrofit會默認new一個。
2. baseUrl(String baseUrl) :設置API地址。
3. addConverterFactory(Converter.Factory factory) :設置一個數據轉化工廠,比如把Json和實體類之間的轉化。
4. addCallAdapterFactory(CallAdapter.Factory factory):設置一個適配器工廠,方便和其他庫配合使用,如RxJava。

另外,如果我們沒有設置執行任務的線程池的話,Retrofit會根據不同的平臺,得到默認的線程池。

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

Android 中默認的線程池:

static class Android extends Platform {
  @Override public Executor defaultCallbackExecutor() {
    return new MainThreadExecutor();
  }

  @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
    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);
    }
  }
}

從上面代碼可以看到,先會創建一個在主線程中的Handler,然後默認線程池執行的任務都是在Android的主線程中執行的,這也是在Retrofit異步回調中我們能直接在裏面更新UI的原因。

另外,Retrofit根據不同使用平臺,會默認添加一個CallAdapterFactory

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

Android 中添加的是ExecutorCallAdapterFactory:

2、通過Retrofit的create方法,實現描述http請求的Java接口。

// Create an instance of our GitHub API interface.
GitHub github = retrofit.create(GitHub.class);
// Create a call instance for looking up Retrofit contributors.
Call<List<Contributor>> call = github.contributors("square", "retrofit");

我們在使用Retrofit時,首先要通過Retrofit實例來得到一個請求接口的實例(github),然後調用這個實例的一個方法(contributors)構造一個Call對象。這個過程主要是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, 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 serviceMethod = loadServiceMethod(method);
          OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
          return serviceMethod.callAdapter.adapt(okHttpCall);
        }
      });
}

當調用接口裏面方法的時候(github.contributors(“square”, “retrofit”) ),會執行InvocationHandler裏面的內容,通過反射,得到調用的method相關信息,然後構造ServiceMethod和OkHttpCall的實例,在Android中通過ExecutorCallAdapterFactory 把 OkHttpCall 進行轉換 ExecutorCallbackCall:

return new CallAdapter<Call<?>>() {
  @Override public Type responseType() {
    return responseType;
  }

  @Override public <R> Call<R> adapt(Call<R> call) {
    return new ExecutorCallbackCall<>(callbackExecutor, call);
  }
};

最後我們得到的Call對象實際上是ExecutorCallbackCall實例。得到Call實例之後,就可以通過call.enqueue進行網絡請求,我們看看ExecutorCallbackCall中的enqueue方法:

@Override public void enqueue(final Callback<T> callback) {
  if (callback == null) throw new NullPointerException("callback == null");

  delegate.enqueue(new Callback<T>() {
    @Override public void onResponse(Call<T> call, final Response<T> response) {
      callbackExecutor.execute(new Runnable() {
        @Override public void run() {
          if (delegate.isCanceled()) {
            // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
            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);
        }
      });
    }
  });
}

在ExecutorCallbackCall中的enqueue裏面,又調用delegate.enqueue方法,這個delegate,其實是OkHttpCall對象,也就是調用OkHttpCall中的enqueue方法。
首先構造一個okhttp中的Request對象:

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的toRequest方法得到的:

Request toRequest(Object... args) throws IOException {
  RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
      contentType, hasBody, isFormEncoded, isMultipart);

  @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
  ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;

  int argumentCount = args != null ? args.length : 0;
  if (argumentCount != handlers.length) {
    throw new IllegalArgumentException("Argument count (" + argumentCount
        + ") doesn't match expected count (" + handlers.length + ")");
  }

  for (int p = 0; p < argumentCount; p++) {
    handlers[p].apply(requestBuilder, args[p]);
  }

  return requestBuilder.build();
}

其中構造RequestBuilder的參數都是ServiceMethod 從Java接口中的註解解析出來的。

ServiceMethod: 從這個類的方法結構可以看出,這個類主要作用是把方法的註解解析成變量保存起來。

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章