天天看點

Retrofit源碼解析Retrofit源碼結構Retrofit和okhttp的關系主要類和方法

Retrofit源碼結構

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

從Retrofit源碼結構可以看出,Retrofit 源碼分成兩部分

Retrofit源碼解析Retrofit源碼結構Retrofit和okhttp的關系主要類和方法

一部分是包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 : ;
  if (argumentCount != handlers.length) {
    throw new IllegalArgumentException("Argument count (" + argumentCount
        + ") doesn't match expected count (" + handlers.length + ")");
  }

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

  return requestBuilder.build();
}
           

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

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

Retrofit源碼解析Retrofit源碼結構Retrofit和okhttp的關系主要類和方法

繼續閱讀