Retrofit2是怎么實現(xiàn)切換線程的

在上一篇Retrofit是如何支持Kotlin協(xié)程的?分析時踢械,并沒有發(fā)現(xiàn)retrofit使用kotlin協(xié)程來切換線程的代碼瞎颗。

那retrofit是在哪里做的線程切換呢坐搔?

val testRetrofit: Retrofit = Retrofit.Builder()
    .addConverterFactory(GsonConverterFactory.create())
    .client(okClient)
    .baseUrl("")
    .build()

val testService: TestServiceApi by lazy { testRetrofit.create(TestServiceApi::class.java)}

首先從create方法入手:

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

              @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);
                }
                args = args != null ? args : emptyArgs;
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

1.Proxy.newProxyInstance 是使用的java.lang.reflect提供的代理類。
2.由Platform platform = Platform.get();可知該方法實現(xiàn)和平臺相關(guān)漠嵌。

追溯Platform.get()咐汞,可以看到:

class Platform {
  private static final Platform PLATFORM = findPlatform();

  static Platform get() {
    return PLATFORM;
  }

  private static Platform findPlatform() {
    return "Dalvik".equals(System.getProperty("java.vm.name"))
        ? new Android() //
        : new Platform(true);
  }
  ......
}

再看Android():

 static final class Android extends Platform {
    Android() {
      super(Build.VERSION.SDK_INT >= 24);
    }

    @Override
    public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Nullable
    @Override
    Object invokeDefaultMethod(
        Method method, Class<?> declaringClass, Object object, Object... args) throws Throwable {
      if (Build.VERSION.SDK_INT < 26) {
        throw new UnsupportedOperationException(
            "Calling default methods on API 24 and 25 is not supported");
      }
      return super.invokeDefaultMethod(method, declaringClass, object, args);
    }

    static final class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override
      public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }

Android類里面的MainThreadExecutor涉及到了線程的切換。好像是找到答案了儒鹿。
再看它是怎么調(diào)用的化撕。追溯defaultCallbackExecutor()方法:

 public Retrofit build() {
      ......
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

      ......
      return new Retrofit(
          callFactory,
          baseUrl,
          unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories),
          callbackExecutor,
          validateEagerly);
    }

這條線到這里已經(jīng)到頭了。再看create方法里面的loadServiceMethod(method).invoke(args)约炎,這里的invoke方法是抽象類ServiceMethod<T>里面的抽象方法invoke植阴。點擊他可以找到它的一個唯一實現(xiàn):

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

這里的 adapt(call, args)方法有三個實現(xiàn)。分別是:


adapt方法的三個實現(xiàn)類

都點進去查看圾浅,


CallAdapted

SuspendForResponse

對比后發(fā)現(xiàn)掠手,他們都調(diào)用了

call = callAdapter.adapt(call);

普通的接口方法調(diào)用,直接返回了狸捕。使用kotlin喷鸽,suspend修飾的接口方法調(diào)用,retrofit增加了網(wǎng)絡(luò)請求的調(diào)用和結(jié)果的返回灸拍。既是: return KotlinExtensions.awaitResponse(call, continuation);

  //這里是獲取接口方法參數(shù)列表的最后一個參數(shù)做祝,
  //這里已經(jīng)確認了是suspend修飾的方法,所以該方法的參數(shù)中的最后一個參數(shù)必定是Continuation類型鸡岗。
  //這里相當于獲取到該方法的回調(diào)的對象剖淀,協(xié)程恢復時就是調(diào)用這個回調(diào)。
 Continuation<Response<ResponseT>> continuation =
          (Continuation<Response<ResponseT>>) args[args.length - 1];

在SuspendForResponse中纤房,callAdapter是外部傳入的纵隔。


構(gòu)造方法賦值
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
      ......

    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
      ......
    if (!isKotlinSuspendFunction) {
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForResponse<>(
              requestFactory,
              callFactory,
              responseConverter,
              (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
    } else {
      ......
    }
  }

這里的createCallAdapter可以追溯到:

 public CallAdapter<?, ?> nextCallAdapter(
    ......
    int start = callAdapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
  ......
  }

這里的callAdapterFactories有點眼熟,原來它在追溯defaultCallbackExecutor()時出現(xiàn)過:

 Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }
 List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
斷點

總結(jié)

refrofit 是通過 在Android平臺的線程切換,是通過handler切換到主線程的捌刮。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末碰煌,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子绅作,更是在濱河造成了極大的恐慌芦圾,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件俄认,死亡現(xiàn)場離奇詭異个少,居然都是意外死亡,警方通過查閱死者的電腦和手機眯杏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進店門夜焦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人岂贩,你說我怎么就攤上這事茫经。” “怎么了萎津?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵卸伞,是天一觀的道長。 經(jīng)常有香客問我锉屈,道長荤傲,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任颈渊,我火速辦了婚禮遂黍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘儡炼。我一直安慰自己妓湘,他們只是感情好,可當我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布乌询。 她就那樣靜靜地躺著榜贴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪妹田。 梳的紋絲不亂的頭發(fā)上唬党,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天,我揣著相機與錄音鬼佣,去河邊找鬼驶拱。 笑死,一個胖子當著我的面吹牛晶衷,可吹牛的內(nèi)容都是我干的蓝纲。 我是一名探鬼主播阴孟,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼税迷!你這毒婦竟也來了永丝?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤箭养,失蹤者是張志新(化名)和其女友劉穎慕嚷,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體毕泌,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡喝检,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了撼泛。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挠说。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖坎弯,靈堂內(nèi)的尸體忽然破棺而出纺涤,到底是詐尸還是另有隱情译暂,我是刑警寧澤抠忘,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站外永,受9級特大地震影響崎脉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜伯顶,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一囚灼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧祭衩,春花似錦灶体、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至路克,卻和暖如春樟结,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背精算。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工瓢宦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人灰羽。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓驮履,卻偏偏與公主長得像鱼辙,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子玫镐,可洞房花燭夜當晚...
    茶點故事閱讀 44,573評論 2 353

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

  • 前言 Retrofit這個強大的網(wǎng)絡(luò)請求庫相信每個做安卓的小伙伴們都不陌生座每,通過簡單的構(gòu)造之后,只需要在creat...
    李曉通閱讀 942評論 7 8
  • 前言 之前講過了okhttp的超級概括的原理解析摘悴,okhttp以它優(yōu)秀的線程池設(shè)計峭梳,任務隊列的分配和轉(zhuǎn)化以及基于責...
    Dex_閱讀 144評論 0 1
  • 在項目開發(fā)中其實最常見的網(wǎng)絡(luò)請求框架就是OkHttp+Retrofit葱椭,在上一篇老生新談,從OkHttp原理看網(wǎng)絡(luò)...
    付十一v閱讀 1,329評論 0 5
  • Retrofit2作為目前最火的網(wǎng)絡(luò)請求框架之一口四,它是一個由Square組織開發(fā)的可以在Android和java中...
    maoqitian閱讀 662評論 0 1
  • Retrofit2 源碼解析 注意: 本文是對源碼的一個跟蹤蔓彩,會對每一行代碼有具體的闡述治笨,但是不會介紹 Retro...
    Yjnull閱讀 2,908評論 3 17