Retrofit 源碼深入分析 —— RxJava 和 協(xié)程的支持

一、概述

在上一篇 Retrofit 源碼深入分析 —— Call 對象的誕生與請求 的文章中我們基本把 Retrofit 從如何構(gòu)建一個(gè)請求到返回響應(yīng)的整個(gè)過程都梳理了一遍负间,對 Retrofit 的基本工作原理有了一個(gè)完整的了解色乾。按照文章的完成度來說提岔,上一篇文章基本把 Retrofit 講的差不多了宰僧,但筆者還是想把日常普遍使用的幾種方式都梳理一遍匪傍,讓兩篇文章對 Retrofit 的分析更加完整您市。

本篇文章其實(shí)按理來說應(yīng)該整合到上一篇中,但這樣讓本就有點(diǎn)長的文章變得更長役衡,對于閱讀來說可能會很累茵休,而對于筆者來說無論是寫還是校對也很累,索性單開一篇手蝎。而且也并不會妨礙彼此的連貫性榕莺。

二、Retrofit 對 RxJava 的支持

讓我們看看如何用 RxJava 的方式進(jìn)行請求柑船,還是用官方 sample 的例子

  • 添加對 RxJava 的支持
addCallAdapterFactory(RxJavaCallAdapterFactory.create())
  • 聲明一個(gè)返回類型為 Obervable 的接口方法
public interface GitHub {
    @GET("/repos/{owner}/{repo}/contributors")
    Observable<List<Contributor>> contributors(@Path("owner") String owner,@Path("repo") String repo);
}
  • 創(chuàng)建接口服務(wù)
GitHub github = retrofit.create(GitHub.class);
  • 發(fā)起一個(gè)請求
 Observable<List<Contributor>> observable = github.contributors("square", "retrofit");
 
  observable.
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Observer<List<Contributor>>() {
            @Override
            public void onCompleted() {}

            @Override
            public void onError(Throwable throwable) { }

            @Override
            public void onNext(List<Contributor> contributors) {
                for (Contributor contributor : contributors) {
                    System.out.println(contributor.login + " (" + contributor.contributions + ")");
                }
            }
    });

上述是一個(gè)標(biāo)準(zhǔn)的支持 RxJava 的請求步驟帽撑,這里與默認(rèn)的請求最大的區(qū)別除了請求的過程不同外,返回的類型由原來的 Call.class 類型變?yōu)榱?Observable.class 類型也就是一個(gè)被觀察者對象鞍时,所以很明顯 RxJavaCallAdapterFactory 內(nèi)部幫我門做了某種轉(zhuǎn)換,至于注解的解析過程都是一樣的亏拉,這里不在贅述。

讓我們再次延續(xù)上篇文章的 6.1 小節(jié)部分逆巍〖疤粒回到創(chuàng)建 CallAdapter 的地方,也就是 createCallAdapter 方法锐极,上篇文章對這個(gè)方法已經(jīng)進(jìn)行了描述笙僚,所以廢話不多說讓我們直接進(jìn)入 RxJavaCallAdapterFactory 的 get 方法

@Override public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    Class<?> rawType = getRawType(returnType);
    boolean isSingle = rawType == Single.class;
    boolean isCompletable = rawType == Completable.class;
    if (rawType != Observable.class && !isSingle && !isCompletable) {
      return null;
    }

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

    boolean isResult = false;
    boolean isBody = false;
    Type responseType;
    
    Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
    Class<?> rawObservableType = getRawType(observableType);
    //Model 不可聲明為 Retrofit 的Response 類型
    if (rawObservableType == Response.class) {
      if (!(observableType instanceof ParameterizedType)) {
        throw new IllegalStateException("Response must be parameterized"
            + " as Response<Foo> or Response<? extends Foo>");
      }
      responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
    } else if (rawObservableType == Result.class) { //也不可聲明為 RxJava 包下的 Result 類型
      if (!(observableType instanceof ParameterizedType)) {
        throw new IllegalStateException("Result must be parameterized"
            + " as Result<Foo> or Result<? extends Foo>");
      }
      responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
      isResult = true;
    } else {
      responseType = observableType;
      isBody = true;
    }

    return new RxJavaCallAdapter(responseType, scheduler, isAsync, isResult, isBody, isSingle,
        false);

RxJavaCallAdapterFactory 的 get 方法的邏輯還是很清晰的,首先創(chuàng)建 RxJavaCallAdapter 的前置條件必須為 Observable灵再、Single 和 Completable 而如果是 Completable 只接創(chuàng)建一個(gè)返回類型為 Void 的 adapter, 至于 Single 和 Completable 肋层,前者在 RxJava 中代表只能處理一次事件亿笤,即只能發(fā)射單個(gè)數(shù)據(jù)或錯(cuò)誤事件。而 Completable 正如它的名字栋猖,它不負(fù)責(zé)發(fā)送數(shù)據(jù)净薛,只會處理 Rxjava 的 conComplete 和 onError 事件。

RxJavaCallAdapter 創(chuàng)建完成后就和 Call 對象的誕生流程差不多了蒲拉。所以讓們直接進(jìn)入其中的 adapt 方法看看 Observable 的真面目

//形參為 OkHttpCall 創(chuàng)建的過程請看上一篇文章
@Override public Object adapt(Call<R> call) {
    OnSubscribe<Response<R>> callFunc = isAsync
        ? new CallEnqueueOnSubscribe<>(call)//異步肃拜,將 OkHttpCall  對象傳入
        : new CallExecuteOnSubscribe<>(call);//同步,將 OkHttpCall 對象傳入

    OnSubscribe<?> func;
    if (isResult) {//聲明類型不是的 RxJava 包下的 Result 類型 默認(rèn) false
      func = new ResultOnSubscribe<>(callFunc);
    } else if (isBody) { //默認(rèn) true
      func = new BodyOnSubscribe<>(callFunc);
    } else {
      func = callFunc;
    }
    //創(chuàng)建一個(gè)被觀察對象
    Observable<?> observable = Observable.create(func);

    if (scheduler != null) {
      observable = observable.subscribeOn(scheduler);
    }

    if (isSingle) {//返回一個(gè) Single 事件
      return observable.toSingle();
    }
    if (isCompletable) {//返回一個(gè) toCompletable 事件
      return observable.toCompletable();
    }
    return observable;
  }

注釋已經(jīng)進(jìn)行了詳細(xì)的解釋就不多說了雌团,由于我們使用的是異步請求燃领,所以肯定創(chuàng)建的是 CallEnqueueOnSubscribe 對象,該對象實(shí)現(xiàn)了 OnSubscribe 接口并重寫了 call 方法锦援,代碼如下

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

代碼并不復(fù)雜猛蔽,可以看到內(nèi)部還是委托 OkHttpCall 的 enqueue 方法來獲取請求的 response ,在經(jīng)過 GsonConvertAdapter 轉(zhuǎn)換后,將該 Response 發(fā)射出去雨涛。那么到這里整個(gè) RxJava 的支持過程就清晰了枢舶。

首先當(dāng)我們把接口的返回類型聲明為 Observable<T> 類型時(shí),會通過 RxJavaCallAdapterFactory 的 get 方法來幫我們創(chuàng)建一個(gè) RxJavaCallAdapter 對象替久,RxJavaCallAdapter 的 adapt 方法中會幫我們創(chuàng)建一個(gè)被觀察者對象返回凉泄。而當(dāng)我們通過如下代碼發(fā)起一個(gè)訂閱

observable.
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Observer());

訂閱完成后,CallEnqueueOnSubscribe 對象的 call 方法就會被觸發(fā)蚯根,剩下的就是在 onNext 方法中接收 Resposne 了后众。

從整體的處理環(huán)節(jié)來看,除了 RxJava 本身的特性之外颅拦,基本的邏輯和默認(rèn)的 Call<T> 類型的處理是差不多的蒂誉。因?yàn)槎际亲裱耐惶捉涌跇?biāo)準(zhǔn)。所以如果你不喜歡默認(rèn)的類型或 Rxjava距帅,完全可以按照 Retorfit 的標(biāo)準(zhǔn)建立一套自己的 callAdapter右锨。

三、Retrofit 對協(xié)程的支持

協(xié)程作為近幾年很火的異步框架碌秸,其簡便的異步操作方式可以說但凡用過的人沒有不喜歡的绍移,其熱度在 Android 領(lǐng)域已經(jīng)有超過 RxJava 的趨勢。而 Retrofit 自然不會甘于人后讥电,在 2.6.x版本以上也對協(xié)程進(jìn)行了支持蹂窖。

如果你還不了解協(xié)程,建議先 Google/Baidu 查詢一下相關(guān)文章了解一番恩敌,否則可能無法無法愉快的閱讀瞬测。

接下來讓還是讓我們以官方 Sample 為例看看 Retrofit 在 Android 開發(fā)中使用協(xié)程的基本流程(下面的步驟是 Kotlin 代碼)

  • 添加基礎(chǔ)依賴

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
//Android 協(xié)程依賴庫
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'
// 包含協(xié)程的 Activity lifecycle 擴(kuò)展
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.3.0"
  • 構(gòu)建 Retrofit 實(shí)例
val API_URL = "https://api.github.com"

val retrofit = Retrofit.Builder()
                .baseUrl(API_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build()
  • 創(chuàng)建掛起函數(shù)
interface Github {
    @GET("/repos/{owner}/{repo}/contributors")
    suspend fun contributors(
        @Path("owner") owner: String,
        @Path("repo") repo: String) : List<Contributor>
}
  • 創(chuàng)建接口服務(wù)
val github = retrofit.create(Github::class.java)
  • 開啟一個(gè)協(xié)程進(jìn)行請求
lifecycleScope.launch{
    val contributors = github.contributors("square", "retrofit")
    for ((login, contributions) in contributors) {
        println("$login ($contributions)")
    }
}

上述流程算是在 Android 中的常用步驟,但在實(shí)際使用中 lifecycleScope.launch 會單獨(dú)封裝不會像上面那樣單獨(dú)拿出來使用。

簡單了解了上面的流程后月趟,我們來看看 Retrofit 是如何對攜程進(jìn)行支持的灯蝴。

3.1、Retrofit 是如何知道我們用的是協(xié)程孝宗?

要想知道這些讓我們回到創(chuàng)建 RequestFactory 的地方(上一篇文章第五節(jié))

     
RequestFactory build() {
      //解析接口方法的注解绽乔,列如 @GET @POST @Headers 的值等等...
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }

      //省略一些判斷代碼...

      //解析形參的注解并獲取注解對應(yīng)的 value
      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
        parameterHandlers[p] =
            parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
      }

      //省略一些判斷代碼...

      return new RequestFactory(this);
}

這里我們重點(diǎn)要關(guān)注的是解析形參的部分也就是 parseParameter 方法,該方法的完整簽名如下

/*
* @p 傳入的循環(huán)索引
* @parameterType 參數(shù)類型 例如 String Int
* @annotations 參數(shù)注解數(shù)組 例如 @Path @Query
* @allowContinuation 是否使用了協(xié)程
*/
 private @Nullable ParameterHandler<?> parseParameter(
        int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {

了解了上面的內(nèi)容碳褒,我們現(xiàn)在再看那個(gè)循環(huán)解析參數(shù)注解的邏輯,如果對協(xié)程不了解的話閱讀這段代碼的時(shí)候你可能會很疑惑看疗,為什么當(dāng)索引 P == lastparameter 的時(shí)候就可以允許支持協(xié)程了沙峻, 而且還有一個(gè)重要的布爾字段那就是 isKotlinSuspendFunction 的改為 true 的過程,可能看了也會讓你迷惑两芳,讓我們進(jìn)入 parseParameter 方法看看關(guān)鍵代碼

 private @Nullable ParameterHandler<?> parseParameter(
        int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
      ParameterHandler<?> result = null;
      //省略參數(shù)解析代碼...

      if (result == null) {
        if (allowContinuation) { //當(dāng) allowContinuation 為 true 也就是最后一個(gè)參數(shù)的索引和注解數(shù)組長度相等
          try {
            //最后一個(gè)參數(shù)類型為 Continuation.class 類型 isKotlinSuspendFunction 為true
            if (Utils.getRawType(parameterType) == Continuation.class) {
              isKotlinSuspendFunction = true;
              return null;
            }
          } catch (NoClassDefFoundError ignored) {
          }
        }
        throw parameterError(method, p, "No Retrofit annotation found.");
      }

      return result;
    }

可以看到表面邏輯倒也沒什么難以理解的摔寨,就是判斷參數(shù)是否為最后一個(gè)并判斷最后一個(gè)參數(shù)是否為 Continuation.class ,奇怪了怖辆,我們并未聲明 Continuation.class 類型的參數(shù)是复,它判斷個(gè)什么?要想解答這些困惑竖螃,我們需要對 suspend 函數(shù)進(jìn)行一下反編譯來看看它在 java 中是個(gè)什么樣子

//kotlin 代碼
 @GET("/repos/{owner}/{repo}/contributors")
suspend fun contributors(
        @Path("owner") owner: String,
        @Path("repo") repo: String) : List<Contributor>

//反編譯后的 Java 代碼
@GET("/repos/{owner}/{repo}/contributors")
@Nullable
Object contributors(
@Path("owner") @NotNull String var1, 
@Path("repo") @NotNull String var2,
@NotNull Continuation var3);

看了上面的反編譯代碼是不是有點(diǎn)恍然大明白的感覺,原來 suspend 轉(zhuǎn)換為 java 代碼后返回的類型變?yōu)榱俗钤嫉?Object ,同時(shí)形參自動增加了一個(gè) Continuation.class 類型的參數(shù)茁肠,至此也就明白了為什么要判斷最后一個(gè)參數(shù)為 Continuation.class 類型才能把 isKotlinSuspendFunction 字段改為 true 的處理邏輯画髓。

3.2、Retrofit 對協(xié)程的處理

上篇文章中筆者故意將協(xié)程相關(guān)代碼隱藏腻格,主要是為了專注非協(xié)程情況下的源碼分析画拾,而本節(jié)將會重點(diǎn)展示協(xié)程相關(guān)代碼,以梳理 Retrofit 對協(xié)程的支持過程

上一節(jié)中我們已經(jīng)明白了 isKotlinSuspendFunction 字段的處理邏輯菜职,現(xiàn)在讓我們把視線轉(zhuǎn)到 HttpServiceMethod 的 parseAnnotations 方法青抛,看看協(xié)程部分的代碼

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
    boolean continuationWantsResponse = false;
    boolean continuationBodyNullable = false;

    Annotation[] annotations = method.getAnnotations();
    Type adapterType;
    //是否為 Suspend 掛起函數(shù),也就是 Kotlin 的協(xié)程
    if (isKotlinSuspendFunction) {
      //獲取所有參數(shù)類型
      Type[] parameterTypes = method.getGenericParameterTypes();
      //獲取參數(shù)類型的下邊界
      Type responseType = Utils.getParameterLowerBound(0,
          (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
      //獲取類型全限定類名并判斷是否為 Response 類型
      if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
        // Unwrap the actual body type from Response<T>.
        responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
        continuationWantsResponse = true; //協(xié)程返回類型為 Response<T> 類型標(biāo)記位 true 
      } else {
        //省略...
      }

      //獲取要適配的 call 類型 酬核,其實(shí)就是創(chuàng)建了一個(gè) ParameterizedType 的實(shí)例蜜另,類型為 call
      adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
      //這里調(diào)用了一個(gè)實(shí)現(xiàn)了 SkipCallbackExecutor 注解的類,
      //ensurePresent 方法主要作用是將原注解數(shù)組替換為 SkipCallbackExecutor 注解
      annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
    } else {
      //獲取要適配的 call 類型
      adapterType = method.getGenericReturnType();
    }

    //省略若干代碼...

    //獲取 OkHttpClient 實(shí)例
    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      //返回的是 Response<T> 類型
      return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>(requestFactory,
          callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
    } else {
      //返回的是 Body 
      return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>(requestFactory,
          callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
          continuationBodyNullable);
    }
  }

注釋解釋的很清楚了愁茁,這里我們重點(diǎn)關(guān)注一下 SkipCallbackExecutorImpl.ensurePresent() 方法蚕钦,代碼如下

 static Annotation[] ensurePresent(Annotation[] annotations) {
    if (Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)) {
      return annotations;
    }
    
    //創(chuàng)建一個(gè)新的注解數(shù)組
    Annotation[] newAnnotations = new Annotation[annotations.length + 1];
    // 利用系統(tǒng)深拷貝將原數(shù)組注解類型替換為 SkipCallbackExecutor 注解
    newAnnotations[0] = SkipCallbackExecutorImpl.INSTANCE;
    System.arraycopy(annotations, 0, newAnnotations, 1, annotations.length);
    return newAnnotations;
  }

看完上面的代碼你可能會覺得這個(gè) SkipCallbackExecutor 似曾相識,還記得 DefaultCallAdapterFactory 的 get 方法嗎

@Override 
public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
  
    //省略若干代碼...
  
    //這里其實(shí)主要的作用是為了判斷是否使用了協(xié)程鹅很,如果實(shí)現(xiàn)了協(xié)程那么則不使用系統(tǒng)的回調(diào)線程并返回null
    final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
        ? null
        : callbackExecutor;

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

      @Override public Call<Object> adapt(Call<Object> call) {
        return executor == null
            ? call // OkHttpCall 對象
            : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }

如此 SkipCallbackExecutor 注解的作用就清晰了嘶居,首先當(dāng)為 Suspend 函數(shù)時(shí),Retrofit 會將原注解進(jìn)行深拷貝變?yōu)?SkipCallbackExecutor 注解類型,然后會在創(chuàng)建 Call 對象的時(shí)候判斷邮屁,如果符合條件則不用默認(rèn)的 Executor , 直接通過 OkHttpCall 進(jìn)行 async / enqueue 請求整袁。

接下來就是協(xié)程和非協(xié)程返回對象的區(qū)別,從上面的代碼中我們可以很清晰的看到佑吝,對于協(xié)程返回有兩種Response 類型坐昙,一種為自定義的 Model , 一種為 responseBody 類型,分別對應(yīng) SuspendForResponse 和 SuspendForBody 對象芋忿。而兩者和非協(xié)程環(huán)境下的 CallAdapted 對象相同炸客,都是 HttpServiceMethod 的子類,所以無論哪種環(huán)境戈钢,拋開其它因素痹仙,兩者的調(diào)用過程都是相同的,即先調(diào)用 invoke 方法創(chuàng)建 OkHttpCall 對象殉了,在調(diào)用 adapt 方法進(jìn)行具體的請求开仰,SuspendForResponse 類的 adapt 方法如下

/*
*  @call 是 OkHttpCall 對象
*  @args 是我們請求的參數(shù) 就是 github.contributors("square", "retrofit")
*/
 @Override 
 protected Object adapt(Call<ResponseT> call, Object[] args) {
      call = callAdapter.adapt(call);

      //獲取參數(shù)列表中的最后一個(gè) continuation 類型參數(shù) ,詳看上面 suspend 反編譯成 Java 代碼
      Continuation<Response<ResponseT>> continuation =
          (Continuation<Response<ResponseT>>) args[args.length - 1];

      // 調(diào)用 Kotlin 擴(kuò)展函數(shù)
      try {
        return KotlinExtensions.awaitResponse(call, continuation);
      } catch (Exception e) {
        return KotlinExtensions.suspendAndThrow(e, continuation);
      }
}

在 Retrofit 源碼中有一個(gè) KotlinExtensions.kt 文件薪铜,是一個(gè) Kotlin 的擴(kuò)展文件众弓,專門用來處理 suspend 函數(shù),我們進(jìn)入 awaitResponse 函數(shù)看看

suspend fun <T : Any> Call<T>.awaitResponse(): Response<T> {
  return suspendCancellableCoroutine { continuation ->
    continuation.invokeOnCancellation {
      cancel()
    }
    //調(diào)用 OkHttpCall 的 enqueue 方法獲取轉(zhuǎn)換后的響應(yīng)(和上篇文章中的過程是一樣的)
    enqueue(object : Callback<T> {
      override fun onResponse(call: Call<T>, response: Response<T>) {
        //喚醒掛起函數(shù)隔箍,返回 response
        //表現(xiàn)形式看開頭通過協(xié)程獲取 model 的代碼
        continuation.resume(response)
      }

      override fun onFailure(call: Call<T>, t: Throwable) {
        //喚醒掛起函數(shù)谓娃,拋出異常
        continuation.resumeWithException(t)
      }
    })
  }
}

注釋解釋的很清楚了,其中 suspendCancellableCoroutine 是創(chuàng)建協(xié)程的方式之一蜒滩,感興趣的可以了解下傻粘。至于 SuspendForBody 對象,它和 SuspendForResponse 的處理過程是一樣的帮掉,這里就不多說了弦悉。

所以回顧整個(gè)流程對于 suspend 函數(shù)的處理步驟如下

  • 如果形參列表的最后一個(gè)參數(shù)是為 Continuation.class 類型,則 isKotlinSuspendFunction 賦值為 true
  • 獲取 suspend 函數(shù)返回類型蟆炊,如果為 Response<T> 類型稽莉,continuationWantsResponse = true
  • 獲取接口方法所有注解,深拷貝替換為 SkipCallbackExecutor 類型涩搓,并以此為條件決定采用默認(rèn)的 Excutor 還是 直接使用 OkHttpCall
  • 根據(jù) continuationWantsResponse 判斷返回 SuspendForResponse 還是 SuspendForBody 對象
  • 在 SuspendForResponse / SuspendForBody 的 adapt 方法中調(diào)用 KotlinExtensions.awaitResponse / awaitNullable 方法獲取 response 并喚起協(xié)程返回?cái)?shù)據(jù)

如果有些地方還是不明白可以跟著筆者的步驟跟進(jìn)源碼一步步看污秆,這樣會更清晰。

四昧甘、結(jié)語

終于良拼,用了兩篇文章將 Retrofit 分析完了,沒有拉下任何一個(gè)常用的關(guān)鍵步驟充边,可以說是非常全面的分析了庸推。而對于自己來說也有種難言的收獲感常侦,文章很長,代碼也是反復(fù)看了很久很久贬媒,而過程中的抓耳撓腮聋亡,反復(fù) debug, 在理解完最后一行源碼的時(shí)候,頓時(shí)有一種通透的舒爽感际乘,久久不能平靜坡倔,這里也吐槽一下自己,其實(shí)關(guān)于 Retrofit 的文章在前幾年就該寫出來脖含,但一直拖到了現(xiàn)在罪塔,再次感到自己是真的懶,以后盡量勤快點(diǎn)吧养葵!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末垢袱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子港柜,更是在濱河造成了極大的恐慌,老刑警劉巖咳榜,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件夏醉,死亡現(xiàn)場離奇詭異,居然都是意外死亡涌韩,警方通過查閱死者的電腦和手機(jī)畔柔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來臣樱,“玉大人靶擦,你說我怎么就攤上這事」秃粒” “怎么了玄捕?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長棚放。 經(jīng)常有香客問我枚粘,道長,這世上最難降的妖魔是什么飘蚯? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任馍迄,我火速辦了婚禮,結(jié)果婚禮上局骤,老公的妹妹穿的比我還像新娘攀圈。我一直安慰自己,他們只是感情好峦甩,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布赘来。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪撕捍。 梳的紋絲不亂的頭發(fā)上拿穴,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天,我揣著相機(jī)與錄音忧风,去河邊找鬼默色。 笑死,一個(gè)胖子當(dāng)著我的面吹牛狮腿,可吹牛的內(nèi)容都是我干的腿宰。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼缘厢,長吁一口氣:“原來是場噩夢啊……” “哼吃度!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起贴硫,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤椿每,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后英遭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體间护,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年挖诸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了汁尺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,716評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡多律,死狀恐怖痴突,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情狼荞,我是刑警寧澤辽装,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站相味,受9級特大地震影響如迟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜攻走,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一殷勘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧昔搂,春花似錦玲销、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽策吠。三九已至,卻和暖如春瘩绒,著一層夾襖步出監(jiān)牢的瞬間猴抹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工锁荔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蟀给,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓阳堕,卻偏偏與公主長得像跋理,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子恬总,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容