Retrofit2源碼解析

本篇文章基于 retrofit2 的 2.5.0 版本。


首先我們想要分析源碼为牍,那就首先要會(huì)使用能颁≡尤常看下簡(jiǎn)單用法:

public interface GitHubService {
    @GET("users/{user}/repos")
    Call<List<Repo>> listRepos(@Path("user") String user);
}
//創(chuàng)建Retrofit對(duì)象
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .build();
//創(chuàng)建service
GitHubService service = retrofit.create(GitHubService.class);
//創(chuàng)建Call
Call<List<Repo>> repos = service.listRepos("octocat");
//開(kāi)始請(qǐng)求
repos.enqueue(new Callback<List<Repo>>() {
    @Override
    public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {

    }
    @Override
    public void onFailure(Call<List<Repo>> call, Throwable t) {

    }
});

1.

從create方法入手,發(fā)現(xiàn)是動(dòng)態(tài)代理劲装。
調(diào)用Platform.get獲取platform胧沫,暫時(shí)不知道是干嘛的昌简,
接著看核心方法是loadServiceMethod(method).invoke(..);

image.png

2.

進(jìn)入loadServiceMethod方法中,找到核心方法parseAnnotations()绒怨。從方法名上看出是解析注解的意思纯赎。

image.png

3.

進(jìn)入parseAnnotations方法中,有兩處核心代碼南蹂。

RequestFactory.parseAnnotations(retrofit, method);

HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);

image.png

4.

先查看第一處核心代碼RequestFactory.parseAnnotations(retrofit, method);
發(fā)現(xiàn)是使用了Builder模式創(chuàng)建了RequestFactory對(duì)象犬金,看里面的方法,發(fā)現(xiàn)有一個(gè)create方法可以使用六剥,進(jìn)入方法里面晚顷。

image.png
image.png
  • 先看第一段代碼RequestBuilder,查看類(lèi)里面的方法疗疟,字面意思是quest的構(gòu)造器该默。
    image.png
  • 再看第二段代碼,用剛才的RequestBuilder對(duì)象創(chuàng)建了一個(gè)okhttp3.Request對(duì)象策彤。查看里面的方法栓袖。知道大概是一個(gè)真正用來(lái)發(fā)起請(qǐng)求的類(lèi)。先記著店诗,還沒(méi)有用到裹刮。
    image.png

5.

現(xiàn)在回到第3個(gè)步驟繼續(xù)。查看第二處核心代碼HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);

image.png

看注釋可以了解到庞瘸,ServiceMethod最好緩存起來(lái)使用捧弃,這樣就能解釋上面第2個(gè)步驟的緩存了。接著往下看核心代碼:
①創(chuàng)建了CallAdapter擦囊。

追蹤方法得知最終是由Retrofit對(duì)象的nextCallAdapter方法獲取违霞,內(nèi)部是從callAdapterFactories這個(gè)List中取出,由于還沒(méi)有查看Retrofit類(lèi)的實(shí)現(xiàn)霜第,暫時(shí)先放著葛家。

②創(chuàng)建了ResponseConverter

追蹤方法最終還是由Retrofit對(duì)象的nextResponseBodyConverter方法獲取,與上一個(gè)類(lèi)似泌类,從converterFactories中取出癞谒,還是先放著。

③獲取callFactory

這個(gè)更直接刃榨,從retrofit中取出成員變量callFactory弹砚。

④傳入4個(gè)參數(shù),創(chuàng)建一個(gè)HttpServiceMethod對(duì)象

最后看看HttpServiceMethod的構(gòu)造方法枢希,發(fā)現(xiàn)只是設(shè)置了變量桌吃。

6.

回到最初開(kāi)始分析時(shí)的代碼loadServiceMethod(method).invoke(..);
loadServiceMethod(method)實(shí)際上返回了HttpServiceMethod對(duì)象,查看里面的invoke方法苞轿。

image.png

其中4個(gè)變量都是構(gòu)造方法傳進(jìn)來(lái)的茅诱,繼續(xù)查看callAdapter.adapt方法逗物。發(fā)現(xiàn)是一個(gè)接口方法。

T adapt(Call<R> call);

現(xiàn)在需要找到CallAdapter實(shí)現(xiàn)類(lèi)瑟俭。從上一步驟知道翎卓,這里的4個(gè)成員變量callAdapter,requestFactory摆寄,callFactory失暴,responseConverter中除了requestFactory是剛才知道怎么創(chuàng)建的,其他都是從Retrofit對(duì)象中取出來(lái)的微饥。

7.

現(xiàn)在需要知道Retrofit對(duì)象是怎么構(gòu)建的逗扒,回到最初的簡(jiǎn)單用法中得知,Retrofit是從Retrofit.Builderbuild方法創(chuàng)建的欠橘。

//創(chuàng)建Retrofit對(duì)象
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .build();

8.

現(xiàn)在從build方法入手矩肩。

/**
 * Create the {@link Retrofit} instance using the configured values.
 * <p>
 * Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link
 * OkHttpClient} will be created and used.
 */
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> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
  callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

  // Make a defensive copy of the converters.
  List<Converter.Factory> converterFactories = new ArrayList<>(
      1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

  // Add the built-in converter factory first. This prevents overriding its behavior but also
  // ensures correct behavior when using converters that consume all types.
  converterFactories.add(new BuiltInConverters());
  converterFactories.addAll(this.converterFactories);
  converterFactories.addAll(platform.defaultConverterFactories());

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

先看注釋?zhuān)靼走@里就是通過(guò)一些配置來(lái)創(chuàng)建一個(gè)Retrofit對(duì)象,即Builder模式肃续。
看到callFactory的創(chuàng)建蛮拔,默認(rèn)是一個(gè)OkHttpClient對(duì)象,這一點(diǎn)注釋也有說(shuō)明痹升。
創(chuàng)建了一個(gè)Executor,使用了platform的defaultCallbackExecutor方法畦韭。
創(chuàng)建了一個(gè)callAdapterFactories的List疼蛾,把默認(rèn)的CallAdapterFactories添加進(jìn)去,還是使用了platform的方法艺配,defaultCallAdapterFactories(callbackExecutor)察郁。
類(lèi)似的實(shí)現(xiàn)方式,創(chuàng)建了converterFactories转唉,也是添加了默認(rèn)的對(duì)象皮钠。
最后創(chuàng)建了一個(gè)Retrofit對(duì)象并返回,把參數(shù)設(shè)置到了對(duì)象中赠法。

現(xiàn)在清楚了第6步驟使用的對(duì)象都是在Retrofit創(chuàng)建時(shí)就已經(jīng)配置好了麦轰,但是我們繼續(xù)查看時(shí),發(fā)現(xiàn)它們都是接口砖织,所以我們需要找出它們的實(shí)際對(duì)象款侵,即是要找出它們實(shí)例化的代碼。

9.

由于默認(rèn)的Executor侧纯,CallAdapter新锈,ConverterFactories都是由Platform的defaultXXXX方法創(chuàng)建的,所以分析一下platform這個(gè)對(duì)象其實(shí)是什么眶熬∶冒剩回到第一步驟块请,Retrofit的create方法的return中的一行代碼。

private final Platform platform = Platform.get();

進(jìn)去看看

private static final Platform PLATFORM = findPlatform();//獲取平臺(tái)

static Platform get() {
  return PLATFORM;
}

private static Platform findPlatform() {
  try {
    Class.forName("android.os.Build");
    if (Build.VERSION.SDK_INT != 0) {
      return new Android();//這里看到Platform對(duì)象其實(shí)就是Android對(duì)象
    }
  } catch (ClassNotFoundException ignored) {
  }
  try {
    Class.forName("java.util.Optional");
    return new Java8();
  } catch (ClassNotFoundException ignored) {
  }
  return new Platform();
}

現(xiàn)在知道了platform其實(shí)就是Android對(duì)象拳缠,我們查看Retrofit的build方法里的platform的調(diào)用:

  • callbackExecutor = platform.defaultCallbackExecutor();
  • platform.defaultCallAdapterFactories(callbackExecutor)
  • platform.defaultConverterFactoriesSize()
  • platform.defaultConverterFactories()
static class Android extends Platform {
  @IgnoreJRERequirement // Guarded by API check.
  @Override boolean isDefaultMethod(Method method) {
    if (Build.VERSION.SDK_INT < 24) {
      return false;
    }
    return method.isDefault();
  }

  //①默認(rèn)的Executor是MainThreadExecutor
  @Override public Executor defaultCallbackExecutor() {
    return new MainThreadExecutor();
  }

  //②默認(rèn)的CallAdapterFactories
  @Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
      @Nullable Executor callbackExecutor) {
    if (callbackExecutor == null) throw new AssertionError();
    //CallAdapterFactory的默認(rèn)對(duì)象墩新,傳入了callbackExecutor
    ExecutorCallAdapterFactory executorFactory = new ExecutorCallAdapterFactory(callbackExecutor);
    return Build.VERSION.SDK_INT >= 24
      ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
      : singletonList(executorFactory);
  }

  //默認(rèn)的CallAdapterFactoriesSize
  @Override int defaultCallAdapterFactoriesSize() {
    return Build.VERSION.SDK_INT >= 24 ? 2 : 1;
  }

  //④默認(rèn)的ConverterFactories
  @Override List<? extends Converter.Factory> defaultConverterFactories() {
    return Build.VERSION.SDK_INT >= 24
        ? singletonList(OptionalConverterFactory.INSTANCE)
        : Collections.<Converter.Factory>emptyList();
  }

  //③默認(rèn)的ConverterFactoriesSize
  @Override int defaultConverterFactoriesSize() {
    return Build.VERSION.SDK_INT >= 24 ? 1 : 0;
  }

  //默認(rèn)的Executor中的execute方法就是用handler發(fā)消息,把操作放到主線(xiàn)程中
  static class MainThreadExecutor implements Executor {
    private final Handler handler = new Handler(Looper.getMainLooper());

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

10.

現(xiàn)在回看第5個(gè)步驟脊凰,發(fā)現(xiàn)了使用的參數(shù)都是由這里的對(duì)象中取出的抖棘,那么可以繼續(xù)分析第6步驟的方法:


image.png

callAdapter的獲取,在nextCallAdapter方法中
核心callAdapterFactories.get(i).get(returnType, annotations, this);

public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
    Annotation[] annotations) {
  ...

  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的默認(rèn)實(shí)現(xiàn)就是ExecutorCallAdapterFactory狸涌,進(jìn)入該類(lèi)查看get方法切省。

@Override public @Nullable CallAdapter<?, ?> get(
    Type returnType, Annotation[] annotations, Retrofit retrofit) {
  ...
  //創(chuàng)建了一個(gè)CallAdapter
  return new CallAdapter<Object, Call<?>>() {
    @Override public Type responseType() {
      return responseType;
    }

    //核心方法
    @Override public Call<Object> adapt(Call<Object> call) {
      return new ExecutorCallbackCall<>(callbackExecutor, call);
    }
  }; 
}

到這里其實(shí)就是callAdapter的實(shí)現(xiàn)了。

11.

繼續(xù)查看adapt方法帕胆,前文得知傳入的call就是new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
查看內(nèi)部類(lèi)ExecutorCallbackCall:

image.png

我們使用時(shí)就是調(diào)用了Call的enqueue方法朝捆,這里看到enqueue方法的真正實(shí)現(xiàn)。
其中delegate是剛才傳入的OkHttpCall對(duì)象懒豹,callbackExecutor我們知道其實(shí)是MainThreadExecutor對(duì)象芙盘,所以這里的enqueue方法中主要做了兩件事:

  • 調(diào)用OkHttpCall的enqueue發(fā)起請(qǐng)求
  • 調(diào)用MainThreadExecutor的execute方法,內(nèi)部其實(shí)就是用主線(xiàn)程的Handler切換到主線(xiàn)程去運(yùn)行脸秽。

我們繼續(xù)查看OkHttpCall的enqueue方法:

@Override public void enqueue(final Callback<T> callback) {
  checkNotNull(callback, "callback == null");

  okhttp3.Call call;
  Throwable failure;

  synchronized (this) {
    if (executed) throw new IllegalStateException("Already executed.");
    executed = true;

    call = rawCall;
    failure = creationFailure;
    if (call == null && failure == null) {
      try {
        //創(chuàng)建okhttp3.Call對(duì)象
        call = rawCall = createRawCall();
      } catch (Throwable t) {
        throwIfFatal(t);
        failure = creationFailure = t;
      }
    }
  }

  if (failure != null) {
    callback.onFailure(this, failure);
    return;
  }

  if (canceled) {
    call.cancel();
  }
  //調(diào)用了okhttp3.Call對(duì)象的enqueue方法
  call.enqueue(new okhttp3.Callback() {
    @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
      Response<T> response;
      try {
        response = parseResponse(rawResponse);
      } catch (Throwable e) {
        throwIfFatal(e);
        callFailure(e);
        return;
      }

      try {
        callback.onResponse(OkHttpCall.this, response);
      } catch (Throwable t) {
        t.printStackTrace();
      }
    }

    @Override public void onFailure(okhttp3.Call call, IOException e) {
      callFailure(e);
    }

    private void callFailure(Throwable e) {
      try {
        callback.onFailure(OkHttpCall.this, e);
      } catch (Throwable t) {
        t.printStackTrace();
      }
    }
  });
}

發(fā)現(xiàn)很長(zhǎng)儒老,其實(shí)里面的主要工作就是:

  • 創(chuàng)建okhttp3.Call的對(duì)象
  • 調(diào)用這個(gè)對(duì)象的enqueue方法

我們來(lái)看一下這個(gè)okhttp3.Call對(duì)象是什么,查看createRawCall()方法:

private okhttp3.Call createRawCall() throws IOException {
  //這個(gè)callFactory其實(shí)就是okhttpClient
  okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
  if (call == null) {
    throw new NullPointerException("Call.Factory returned null.");
  }
  return call;
}

由上文得知這里的callFactory就是Retrofit.build()中創(chuàng)建的OkhttpClient對(duì)象记餐。
這里的newCall方法就是創(chuàng)建一個(gè)OkHttp的Call了驮樊,所以說(shuō)Retrofit是基于OkHttp來(lái)實(shí)現(xiàn)的。

@Override public Call newCall(Request request) {
  return RealCall.newRealCall(this, request, false /* for web socket */);
}

總結(jié)

  1. 調(diào)用Retrofit.Builder的build方法片酝,初始化必要的參數(shù)囚衔。
    有baseUrl、callFactory雕沿、callbackExecutor练湿、callAdapterFactories、converterFactories等审轮。
  2. 調(diào)用retrofit的create方法肥哎,包裝出一個(gè)自定義的接口GitHubService的Class。
    內(nèi)部實(shí)現(xiàn)是動(dòng)態(tài)代理断国,具體實(shí)現(xiàn)是HttpServiceMethod的對(duì)象贤姆。其中包含了對(duì)接口方法注解的解析。
  3. 最后調(diào)用enqueue發(fā)起請(qǐng)求內(nèi)部使用了okhttp稳衬。

謝謝大家能看到末尾霞捡,如果發(fā)現(xiàn)有錯(cuò)誤的地方或者有疑問(wèn)的地方請(qǐng)各位留言,謝謝薄疚!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末碧信,一起剝皮案震驚了整個(gè)濱河市赊琳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌砰碴,老刑警劉巖躏筏,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異呈枉,居然都是意外死亡趁尼,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)猖辫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)酥泞,“玉大人,你說(shuō)我怎么就攤上這事啃憎≈ザ冢” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵辛萍,是天一觀的道長(zhǎng)悯姊。 經(jīng)常有香客問(wèn)我,道長(zhǎng)贩毕,這世上最難降的妖魔是什么悯许? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮辉阶,結(jié)果婚禮上岸晦,老公的妹妹穿的比我還像新娘。我一直安慰自己睛藻,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布邢隧。 她就那樣靜靜地躺著店印,像睡著了一般。 火紅的嫁衣襯著肌膚如雪倒慧。 梳的紋絲不亂的頭發(fā)上按摘,一...
    開(kāi)封第一講書(shū)人閱讀 51,365評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音纫谅,去河邊找鬼炫贤。 笑死,一個(gè)胖子當(dāng)著我的面吹牛付秕,可吹牛的內(nèi)容都是我干的兰珍。 我是一名探鬼主播询吴,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼亮元,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼唠摹!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起勾拉,我...
    開(kāi)封第一講書(shū)人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎藕赞,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體找默,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年店煞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片顷蟀。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡骡技,死狀恐怖鸣个,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情布朦,我是刑警寧澤囤萤,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站是趴,受9級(jí)特大地震影響涛舍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜唆途,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一富雅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧肛搬,春花似錦没佑、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春远剩,著一層夾襖步出監(jiān)牢的瞬間扣溺,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工瓜晤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留锥余,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓痢掠,卻偏偏與公主長(zhǎng)得像驱犹,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子足画,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

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

  • 目錄介紹 1.首先回顧Retrofit簡(jiǎn)單使用方法 2.Retrofit的創(chuàng)建流程源碼分析2.1 Retrofit...
    楊充211閱讀 1,058評(píng)論 0 16
  • 一雄驹、什么是Retrofit A type-safe HTTP client for Android and Jav...
    andcoder閱讀 770評(píng)論 2 3
  • 適配器模式上一篇文章我們已經(jīng)分析了Retrofit解析注解封裝進(jìn)ServiceMethod的流程,讀者在這里要記住...
    andcoder閱讀 657評(píng)論 0 2
  • 本文將順著構(gòu)建請(qǐng)求對(duì)象->構(gòu)建請(qǐng)求接口->發(fā)起同步/異步請(qǐng)求的流程淹辞,分析Retrofit是如何實(shí)現(xiàn)的医舆。 開(kāi)始之前,...
    zhuhf閱讀 1,619評(píng)論 0 10
  • 《莊子·山木》篇里講了一個(gè)小故事: 一個(gè)人在乘船渡河的時(shí)候象缀,前面一只船正要撞過(guò)來(lái)蔬将。 這個(gè)人喊了好幾聲沒(méi)有人回應(yīng), ...
    趙肅江閱讀 1,215評(píng)論 0 0