一張圖帶你走進Retrofit原始碼世界

cuieney發表於2017-08-29

前提

只有瞭解了框架的原理才能更好的使用她,才能定位問題的根本。寫這篇文章的也是為了自我的學習和提升。其實看原始碼就跟看書一樣,看了這麼多本書有什麼用呢,其實不然,這些知識已經潛移默化的影響了你的思維。你之後在閱讀原始碼時,會發現能更快的上手了。

引用別人的一句話:當我還是個孩子時吃的很多食物,大部分已經一去不復返而且被我忘掉了,但可以肯定的是,它們中的一部分已經長成我的骨頭和肉

友情提醒

1.這篇文章主要講retrofit如何request 和 response
2.不會詳細到每個api
3.文章會以一個flow 來講解

上圖

如果下圖有錯誤歡迎評論指正,如果看不清你可以下載下來放大看,應該會好點。我們這次會以這個圖的flow 來講解(主要是左半邊)。

retrofit_flow.png
retrofit_flow.png

retrofit初始化配置

這裡講解的就是上圖中的adapterFactories,我們們這邊以RxjavaAdapter來講解,下面是一些retrofit的初始化配置。

 private Retrofit createRetrofit(OkHttpClient client, String url) {
        return new Retrofit.Builder()
                .baseUrl(url)
                .client(client)
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }複製程式碼

這裡我們只說一下主要的東西,大家都知道retrofit的adapter 我們根據我們api請求的不同設定不同的adapter來讓retrofit執行不同的操作,當我們在設定他的CallAdapter時,點進原始碼可以看到,retrofit把這個CallAdapter存入了一個集合中

final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();複製程式碼

然後通過build把這個集合回傳給了retrofit的這個全域性邊變數List<CallAdapter.Factory> adapterFactories儲存著這些CallAdapter,仔細看的同學會發現,retrofit會預設給你新增一個CallAdapter

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);

      //這裡就是預設的adapter 防止使用者未設定。
      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);
    }
  }複製程式碼

以上就說到這裡,知道有個CallAdapterFactory集合存在Retrofit的全域性變數中。

配置Api

這裡講解的是圖中的這方法create(final Class<T> service)稍微提一下吧。上面的adapter其實是根據你在Api中配置的返回引數有關。當我們要使用Rxjava時我們傳對應的Rxjava的adapter 如果我們配置的是okhttp的Call回撥,自然我們都不需要配置adapter,retrofit都給我們預設配置好了,下圖可以看到兩種不同的response

public interface Api {

    @Multipart
    @POST("upload")
    Observable<BaseBean> postVoice(@Part("deviceNo") RequestBody deviceNo,
                                   @Part("duration") RequestBody duration,
                                   @Part("title") RequestBody title,
                                   @Part MultipartBody.Part file);
    @GET("selfList")
    Call<VoiceList> getVoiceList(@Query("deviceNo")String deviceNo);

}複製程式碼

Request

這裡講解的是上圖中的
create(final Class<T> service)ServiceMethod

當我們要發起請求的時候,我們是不是這樣做,拿到之前配置好的Retrofit然後呼叫他的Create方法然後把相應的api傳入.
Retroift.create(Api.class)這樣的操作

現在我們進入原始碼檢視這個retrofit最亮點的地方(create(api.class)),通過反射例項化介面,然後攔截介面中的方法,來做api的請求。返回給這個method。

先把原始碼晾上然後講解

 public <T> T create(final Class<T> 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 {
                   ·······省略的程式碼·······
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }複製程式碼

上面的程式碼已經是把無關緊要的程式碼剔除了,我們只看重要的程式碼

  • 我們可以看到create這個方法通過代理反射例項化我們傳進來的api介面
  • 然後通過ServiceMethodOkHttpCall來拿到這個方法的相關引數,來invoke這個方法
  • 最後通過serviceMethod.callAdapter.adapt(okHttpCall)把請求到的值返回回去

其實在最後一步大家應該明白了,請求是來自於ServiceMethod的callAdapter引數,然後通過adapt來進行okhttp請求。

下面我會講解這個calladapter 如何而來。

ServiceMethod如何發起請求

這是一個流程哈,我們這時候進入程式碼core部分,他的ServiceMethod時通過retrofit的loadServiceMethod拿到的例項化物件。我們進入這個方法可以看到其實這是一個全域性的ServiceMethod的cacheMap

 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;
  }複製程式碼

但是不論他做不做快取肯定有new 的地方,然後才能加入快取中吧。從上圖程式碼中我們可以看到這個new 的地方。

if (result == null) {
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }複製程式碼

這下清楚了ServiceMethod哪裡來的了吧,通過new ServiceMethod.Builder<>(this, method).build()這句話來的。看原始碼不都這樣嗎!一步一步的進入原始碼然後理解他的每一層 意思和目的。to be continue

上ServiceMethod.Builder的原始碼,我們只看重要的程式碼,其他的忽略

 Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

    public ServiceMethod build() {
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();
      ·······省略的程式碼·······
      }複製程式碼

小夥子們,是不是看到了我們一直最關心的calladapter了,在build的時候通過createCallAdapter來初始化了這個值。進入方法看個究竟

private CallAdapter<T, R> createCallAdapter() {
      Type returnType = method.getGenericReturnType();
      ·······省略的程式碼·······
      Annotation[] annotations = method.getAnnotations();
      try {
        ····敲黑板,敲黑板,敲黑板·····
        return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
      } catch (RuntimeException e) { // Wide exception range because factories are user code.
        throw methodError(e, "Unable to create call adapter for %s", returnType);
      }
    }複製程式碼

看到了吧,小夥伴這個calladapter 來自於retrofit裡面的方法,我們在loadServiceMethod的時候還記得這句程式碼嗎?new ServiceMethod.Builder<>(this, method).build()我們把retrofit傳了進來,然後這裡通過retrofit的callAdapter來獲取ServiceMethod的adapter。下面是retrofit的原始碼獲取c

 public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }複製程式碼
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
   ·······省略的程式碼·······
   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;
      }
    }

  ·······省略的程式碼·······
  }複製程式碼

我感覺只要不眼瞎都能看到這個serviceMethod的calladapter 是來自於我們retrofit之前進行初始化配置時候的RxJavaCallAdapterFactory.create()
其實我們可以在之前的圖中看到這個flow,.addCallAdapterFactory(RxJavaCallAdapterFactory.create())最終指向的是ServiceMethod的CallAdapter。

進入RxJavaCallAdapterFactory的原始碼吧。其實這裡的程式碼並不多,只不過有些雜亂。下面我會把不需要的程式碼過濾

public final class RxJavaCallAdapterFactory extends CallAdapter.Factory {
  /**
   * Returns an instance which creates synchronous observables that do not operate on any scheduler
   * by default.
   */
  public static RxJavaCallAdapterFactory create() {
    return new RxJavaCallAdapterFactory(null, false);
  }

  /**
   * Returns an instance which creates asynchronous observables. Applying
   * {@link Observable#subscribeOn} has no effect on stream types created by this factory.
   */
  public static RxJavaCallAdapterFactory createAsync() {
    return new RxJavaCallAdapterFactory(null, true);
  }

  /**
   * Returns an instance which creates synchronous observables that
   * {@linkplain Observable#subscribeOn(Scheduler) subscribe on} {@code scheduler} by default.
   */
  @SuppressWarnings("ConstantConditions") // Guarding public API nullability.
  public static RxJavaCallAdapterFactory createWithScheduler(Scheduler scheduler) {
    if (scheduler == null) throw new NullPointerException("scheduler == null");
    return new RxJavaCallAdapterFactory(scheduler, false);
  }

  private final @Nullable Scheduler scheduler;
  private final boolean isAsync;

  private RxJavaCallAdapterFactory(@Nullable Scheduler scheduler, boolean isAsync) {
    this.scheduler = scheduler;
    this.isAsync = isAsync;
  }

@Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
   ·······省略的程式碼·······

    if (isCompletable) {
      return new RxJavaCallAdapter(Void.class, scheduler, isAsync, false, true, false, true);
    }

   ·······省略的程式碼·······

    return new RxJavaCallAdapter(responseType, scheduler, isAsync, isResult, isBody, isSingle,
        false);
  }
}複製程式碼

可以看到這個RxJavaCallAdapterFactory繼承了CallAdapter.Factory,實現了他的get方法,在get方法中我們就可以拿到這個CallAdapter,然後進行我們的adapt方法請求。
從上面的程式碼可以看到真正實現CallAdapter的是
RxJavaCallAdapter 我們繼續看看這個RxJavaCallAdapter到底幹了什麼!!!同樣我會過濾不需要的程式碼

final class RxJavaCallAdapter<R> implements CallAdapter<R, Object> {
·······省略的程式碼·······

   @Override public Object adapt(Call<R> call) {
    OnSubscribe<Response<R>> callFunc = isAsync
        ? new CallEnqueueOnSubscribe<>(call)
        : new CallExecuteOnSubscribe<>(call);

    OnSubscribe<?> func;
    if (isResult) {
      func = new ResultOnSubscribe<>(callFunc);
    } else if (isBody) {
      func = new BodyOnSubscribe<>(callFunc);
    } else {
      func = callFunc;
    }
    Observable<?> observable = Observable.create(func);

   ·······省略的程式碼·······

    return observable;
  }
}複製程式碼

好了,這下清晰了許多
_這個RxJavaCallAdapter實現了CallAdapter的adapt請求。然後在adapt中需要傳入引數就是Call 然而我們可以回到圖中看到,OkHttpCall正好是Call的實現類。這裡就是上圖中的右邊部分。_
可以在這個方法中看到了,同步非同步請求對應的不一樣的然後呼叫不同的CallEnqueueOnSubscribe,CallExecuteOnSubscribe進行request
進入CallEnqueueOnSubscribe原始碼看看

final class CallEnqueueOnSubscribe<T> implements OnSubscribe<Response<T>> {
  private final Call<T> originalCall;

  CallEnqueueOnSubscribe(Call<T> originalCall) {
    this.originalCall = originalCall;
  }

  @Override public void call(Subscriber<? super Response<T>> subscriber) {
    // Since Call is a one-shot type, clone it for each new subscriber.
    Call<T> call = originalCall.clone();
    final CallArbiter<T> arbiter = new CallArbiter<>(call, subscriber);
    subscriber.add(arbiter);
    subscriber.setProducer(arbiter);

    call.enqueue(new Callback<T>() {
      @Override public void onResponse(Call<T> call, Response<T> response) {
        arbiter.emitResponse(response);
      }

      @Override public void onFailure(Call<T> call, Throwable t) {
        Exceptions.throwIfFatal(t);
        arbiter.emitError(t);
      }
    });
  }
}複製程式碼

看到了吧這裡終於發起請求了可以看到,執行了OkHttpCall.enqueue請求,同時通過arbiter.emitResponse(response);把引數回撥了回來。

這就是retrofit的請求flow。

思路整理

  1. 配置retrofit(addCallAdapterFactory)
  2. 建立ApiService
  3. 通過retrofit的create例項化ApiService介面
  4. 建立ServiceMethod
  5. 通過retrofit的AdapterFactories拿到ServiceMethod的CallAdapter
  6. 建立OkHttpCall請求工具類
  7. 通過ServiceMethod的CallAdapter的adapt進行請求並把第六步寫好的call當引數傳給adapt。
  8. 把ServiceMethod請求回來的引數返回給對應的ApiService裡面的方法
  9. 請求完成

ending

嘿嘿嘿,小夥伴們上面有什麼錯誤的話或者不懂得都可以在留言中提及了,小編會在看到的第一時間響應。

To Be Continued

相關文章