Android Retrofit2 源碼分析(一)—— Retroift 的構(gòu)建

Retrofit2 簡介

做為當(dāng)前 Android 最主流的網(wǎng)絡(luò)框架(我個(gè)人認(rèn)為)。

它基于 OkHttp3(square 的代表作) 做了十分優(yōu)雅的封裝,同時(shí)它作為大名鼎鼎的 square 公司的產(chǎn)品疹味,我就不詳細(xì)說它對 OkHttp3 的封裝做到啥地步了
(^ _ ^")术徊。

它可以通過十分簡單的配置盖腕,來很好的滿足各種業(yè)務(wù)場景钝域,比如說可以使用自定義的適配器,轉(zhuǎn)換器(這里最重要的是它可以和 RxJava 完美的相結(jié)合)妇萄,代碼簡直優(yōu)雅了十倍不止蜕企,同時(shí)它的使用也十分簡單,可以通過不同的注解來定制一個(gè) request...

它的功能我也不多說了冠句,上面說的可能有點(diǎn)夸張轻掩,但我做為一個(gè) Android 開發(fā)的小白那是對它推崇至極,贊不絕口懦底!

接下來我將對如何構(gòu)建一個(gè) Retrofit 來做一個(gè)分析唇牧。

Retrofit 簡單用例

apiService = new Retrofit.Builder().client(OkHttpManager.getInstance())
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .baseUrl(ApiSetting.SERVER_URL)
                    .build()
                    .create(ApiService.class);

以上是我自己一個(gè)項(xiàng)目中創(chuàng)建 Retrofit 服務(wù)代理的代碼,這里我們就根據(jù)這個(gè)流程,具體的去分析 Retrofit 的實(shí)現(xiàn)原理奋构。

其實(shí)在 build() 方法之前壳影,無非都是做一些配置,所以我們將重點(diǎn)放在 build() 方法和 creat() 方法中弥臼。

走進(jìn)源碼

build() 方法

先看源碼

    public Retrofit build() {
      //如果 baseUrl 為空宴咧,那么拋出異常(Url都為空了,那還訪問啥)
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      //這里的 callFactory径缅,就是我們上面示例中的自定義的 okhttp client, 
      //如果我們配置自定義的 client 的話掺栅,那么這里直接 new 一個(gè)默認(rèn)的 client    
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      //這里則配置執(zhí)行后的回調(diào),我的示例中并沒有配置  
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        //這里跟 Builder 的時(shí)候有關(guān)纳猪,如果是 Android 環(huán)境下氧卧,那么會(huì)返回一個(gè)默認(rèn)的 CallbackExecutor
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // Make a defensive copy of the adapters and add the default Call adapter.
      //這里就是我們配置的適配器,在示例中氏堤,我添加了RxJava 的相關(guān)適配器
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      //添加完我們添加的適配器 后會(huì)自動(dòng)添加必須的適配器沙绝,這里的設(shè)置的回調(diào)便是上面的 callbackExecutor
      callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // Make a defensive copy of the converters.
      
      //這里就是添加變流器的流程了,類似于適配器的添加鼠锈,我們這里添加了 Gson 的相關(guān)轉(zhuǎn)換器
      List<Converter.Factory> converterFactories =
          new ArrayList<>(1 + this.converterFactories.size());

      // Add the built-in converter factory first. This prevents overriding its behavior but also
      // ensures correct behavior when using converters that consume all types.
      
      //但是有一點(diǎn)不同的是闪檬,上面的適配器是先添加用戶的再添加默認(rèn)的,這里是反了一下购笆,先添加默認(rèn)的粗悯,再添加用戶的。
      converterFactories.add(new BuiltInConverters());
      converterFactories.addAll(this.converterFactories);

      //這里依據(jù)我們配置的各種參數(shù)來生成一個(gè) retrofit 的實(shí)例    
      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }

build 的流程非常簡單同欠,跟我們平常使用構(gòu)造者模式的流程差不多样傍,根據(jù)一系列的配置,最后在 build 方法中根據(jù)用戶的配置和默認(rèn)的設(shè)置創(chuàng)建出一個(gè)可以符合用戶需求的對象铺遂。

接下來我們來看下衫哥,Retrofit 為我們添加的默認(rèn)功能都做了什么。

默認(rèn)添加的適配器

build() 方法中為我們添加了默認(rèn)的適配器

callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

這里傳入了上面創(chuàng)建的 callbackExecutor娃循,我們點(diǎn)進(jìn)去看一下炕檩。

  CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    // 如果 callbackExecutor 不為空斗蒋,那么創(chuàng)建一個(gè) ExecutorCallAdapterFactory
    if (callbackExecutor != null) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }
    // 不然返回 DefaultCallAdapterFactory
    return DefaultCallAdapterFactory.INSTANCE;
  }

這里對之前傳入的 callbackExecutor 做了判空捌斧,并返回不同結(jié)果,我們再回去看下 callbackExecutor 的創(chuàng)建泉沾。

  if (callbackExecutor == null) {
    callbackExecutor = platform.defaultCallbackExecutor();
  }

如果我們沒有配置 callbackExecutor 的話捞蚂,系統(tǒng)就會(huì)調(diào)用 platform.defaultCallbackExecutor()

不說了跷究,再進(jìn)去看下姓迅!

  @Nullable Executor defaultCallbackExecutor() {
   return null;
 }

納尼?返回的是 null,其實(shí)不是丁存,這里我們先去看 Builder() 方法

    public Builder() {
      this(Platform.get());
    }

這里調(diào)用了 Platform.get() 方法

  private static final Platform PLATFORM = findPlatform();

  static Platform get() {
    return PLATFORM;
  }

PLATFORM 是調(diào)用了 findPlatform() 方法

  private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        //這里可以看到 new 了一個(gè) Androdi 對象
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }
  static class Android extends Platform {
   //在 Android 環(huán)境下肩杈,調(diào)用 platform.defaultCallbackExecutor() 就是這里
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }
    @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      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);
      }
    }
  }

可以看到調(diào)用 platform.defaultCallbackExecutor() 的話,會(huì)生成 MainThreadExecutor

所以我們在 Android 中使用的話解寝,一般不會(huì)返回 DefaultCallAdapterFactory.INSTANCE扩然。

但是 DefaultCallAdapterFactory 的代碼十分簡單,我們可以去了解下聋伦。

那我們先看下 DefaultCallAdapterFactory 的作用夫偶。

DefaultCallAdapterFactory

/**
 * Creates call adapters for that uses the same thread for both I/O and application-level
 * callbacks. For synchronous calls this is the application thread making the request; for
 * asynchronous calls this is a thread provided by OkHttp's dispatcher.
 */
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
  static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();

  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    //如果我們 ApiService 接口中請求中返回的類型不是 Call 對象,那么就返回 null
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    
    //1
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) { 
        //直接返回 call
        return call;
      }
    };
  }
}

對于這段代碼觉增,先看它的注釋兵拢,大致意思是回調(diào)和請求在同一線程,如果是異步請求逾礁,這個(gè)線程有 OkHttp 提供说铃。

然后我們再去看下注釋 1 的 Utils.getCallResponseType(returnType) 方法作用

  static Type getCallResponseType(Type returnType) {
    // 這里對返回類型做了判斷,如果不是 Call<Foo> 或者 Call<? extent Foo>嘹履,那么就拋出異常截汪。
    if (!(returnType instanceof ParameterizedType)) {
      throw new IllegalArgumentException(
          "Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
    }
    // 返回獲取到的返回值類型,以便后續(xù) Conveeter 做類型轉(zhuǎn)換
    return getParameterUpperBound(0, (ParameterizedType) returnType);
  }

現(xiàn)在可以知道之前注釋1 中的代碼是用來獲取請求返回值類型的植捎。

DefaultCallAdapterFactory 作用總結(jié)

根據(jù)上面的分析衙解,可以知道 DefaultCallAdapterFactory 中 回調(diào)和請求在同一線程,如果是異步請求焰枢,這個(gè)線程由 OkHttp 提供蚓峦,而且對獲取到的 Call 不做處理,直接返回济锄。

接下來去分析下 ExecutorCallAdapterFactory, 因?yàn)槲覀兪褂玫臅r(shí)候暑椰,它才是默認(rèn)的 CallAdapter。

ExecutorCallAdapterFactory

final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
  final Executor callbackExecutor;

  ExecutorCallAdapterFactory(Executor callbackExecutor) {
    this.callbackExecutor = callbackExecutor;
  }

  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        //1
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }
  ······
 }

基本上和 DefaultCallAdapterFactory 一樣荐绝,有了上面 DefaultCallAdapterFactory 的源碼分析一汽,這里就不多做介紹,唯一不同的是 adapt 方法中低滩,
它 new 了一個(gè) ExecutorCallbackCall 對象召夹,這里就是請求之后的回調(diào),關(guān)于這里具體的內(nèi)容恕沫,我打算在之后的 Retrofit 動(dòng)態(tài)代理相關(guān)的內(nèi)容去說监憎,我們現(xiàn)在只需要知道它的作用就好了。

默認(rèn)添加的 轉(zhuǎn)換器(變流器)

接下來我們來看下婶溯,Retrofit 為我們添加的鲸阔,而且特意添加到第一個(gè)位置的 BuiltInConverter偷霉。

BuiltInConverter

  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    //如果返回?cái)?shù)據(jù)的類型是 ResponseBody
    if (type == ResponseBody.class) {
      //這里根據(jù)數(shù)據(jù)處理是在 streaming 還是 buffer中做了判斷,因?yàn)閮烧咛幚矸绞讲煌稚福苑珠_處理类少。
      return Utils.isAnnotationPresent(annotations, Streaming.class)
          ? StreamingResponseBodyConverter.INSTANCE
          : BufferingResponseBodyConverter.INSTANCE;
    }
    //這一步的意圖在于安全退出相關(guān)操作
    if (type == Void.class) {
      return VoidResponseBodyConverter.INSTANCE;
    }
    return null;
  }

  @Override
  public Converter<?, RequestBody> requestBodyConverter(Type type,
      Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
    //這里判斷請求的類型是不是 OkHttp 中的 RequestBody,因?yàn)?Retrofit 就是對 OkHttp 做了十分棒的封裝渔扎。 
    if (RequestBody.class.isAssignableFrom(Utils.getRawType(type))) {
      return RequestBodyConverter.INSTANCE;
    }
    return null;
  }

這里我直接貼了 BuiltInConverter 唯二的方法瞒滴,一個(gè)做為返回 body 的處理(responseBodyConverter),一個(gè)做為請求 body 的處理(requestBodyConverter)赞警。

兩者其實(shí)都是對數(shù)據(jù)的類型或者環(huán)境做了判斷妓忍,并給予不同的處理方式。

以上涉及到的各種 Converter 都是 BuiltInConverter 的內(nèi)部類愧旦,作用都跟名字一樣清晰世剖,代碼也十分簡單,沒什么復(fù)雜的操作笤虫,我這里貼一下就不詳解了旁瘫,如下。

static final class VoidResponseBodyConverter implements Converter<ResponseBody, Void> {
    static final VoidResponseBodyConverter INSTANCE = new VoidResponseBodyConverter();

    @Override public Void convert(ResponseBody value) {
      value.close();
      return null;
    }
  }

  static final class RequestBodyConverter implements Converter<RequestBody, RequestBody> {
    static final RequestBodyConverter INSTANCE = new RequestBodyConverter();

    @Override public RequestBody convert(RequestBody value) {
      return value;
    }
  }

  static final class StreamingResponseBodyConverter
      implements Converter<ResponseBody, ResponseBody> {
    static final StreamingResponseBodyConverter INSTANCE = new StreamingResponseBodyConverter();

    @Override public ResponseBody convert(ResponseBody value) {
      return value;
    }
  }

  static final class BufferingResponseBodyConverter
      implements Converter<ResponseBody, ResponseBody> {
    static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter();

    @Override public ResponseBody convert(ResponseBody value) throws IOException {
      try {
        // Buffer the entire body to avoid future I/O.
        return Utils.buffer(value);
      } finally {
        value.close();
      }
    }
  }

  static final class ToStringConverter implements Converter<Object, String> {
    static final ToStringConverter INSTANCE = new ToStringConverter();

    @Override public String convert(Object value) {
      return value.toString();
    }
  }

BuiltInConverter 作用總結(jié)

其實(shí)它就是起到一個(gè)統(tǒng)籌的作用琼蚯,做為 Retrofit 的內(nèi)置 Converter酬凳,它根據(jù)需要處理的對象的類型以及環(huán)境不同來調(diào)用相適應(yīng)的 Converter 來處理對應(yīng)的任務(wù)。

Retroift 的 構(gòu)造方法

其實(shí)到這里遭庶,我們已經(jīng)差不多分析完了 Retrofit 默認(rèn)配置的一些模塊宁仔,我們回到 build() 方法中的最后一步。

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

這里就是創(chuàng)建了一個(gè) retrofit 實(shí)例

  Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
      List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories,
      @Nullable Executor callbackExecutor, boolean validateEagerly) {
    this.callFactory = callFactory;
    this.baseUrl = baseUrl;
    this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
    this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
    this.callbackExecutor = callbackExecutor;
    this.validateEagerly = validateEagerly;
  }

到最后很簡單峦睡,將配置好的參數(shù)都做為 Retrofit 構(gòu)造時(shí)的初始值翎苫。

最后 Retrofit 是如何運(yùn)用我們配置好的適配器,轉(zhuǎn)換器等等工具呢榨了。

還記得簡單用例中最后的 create() 方法嗎煎谍,Retrofit 在這個(gè)方法中,使用動(dòng)態(tài)代理創(chuàng)建了一個(gè)代理供我們使用龙屉,而我們配置的這些適配器轉(zhuǎn)換器等工具將在這里使用呐粘,Retrofit 會(huì)很智能的根據(jù)這些參數(shù)來生成我們想要的代理,我們只需要負(fù)責(zé)用就好了转捕。

總結(jié)

這就是 Retrofit 關(guān)于 build 的源碼分析作岖,后面我會(huì)再深入到 create() 方法中,去看一下 Retrofit 最為核心的代碼瓜富,是如何實(shí)現(xiàn)的鳍咱。

Android Retrofit2 源碼分析(二)—— Retrofit 的動(dòng)態(tài)代理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末降盹,一起剝皮案震驚了整個(gè)濱河市与柑,隨后出現(xiàn)的幾起案子谤辜,更是在濱河造成了極大的恐慌,老刑警劉巖价捧,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丑念,死亡現(xiàn)場離奇詭異,居然都是意外死亡结蟋,警方通過查閱死者的電腦和手機(jī)脯倚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嵌屎,“玉大人推正,你說我怎么就攤上這事”Χ瑁” “怎么了植榕?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長尼夺。 經(jīng)常有香客問我尊残,道長,這世上最難降的妖魔是什么淤堵? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任寝衫,我火速辦了婚禮,結(jié)果婚禮上拐邪,老公的妹妹穿的比我還像新娘慰毅。我一直安慰自己,他們只是感情好扎阶,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布事富。 她就那樣靜靜地躺著,像睡著了一般乘陪。 火紅的嫁衣襯著肌膚如雪统台。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天啡邑,我揣著相機(jī)與錄音贱勃,去河邊找鬼。 笑死谤逼,一個(gè)胖子當(dāng)著我的面吹牛贵扰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播流部,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼戚绕,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了枝冀?” 一聲冷哼從身側(cè)響起舞丛,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤耘子,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后球切,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谷誓,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年吨凑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了捍歪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,902評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鸵钝,死狀恐怖糙臼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情恩商,我是刑警寧澤弓摘,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站痕届,受9級特大地震影響韧献,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜研叫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一锤窑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧嚷炉,春花似錦渊啰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至哗讥,卻和暖如春嚷那,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背杆煞。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工魏宽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人决乎。 一個(gè)月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓队询,卻偏偏與公主長得像,于是被迫代替她去往敵國和親构诚。 傳聞我的和親對象是個(gè)殘疾皇子蚌斩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評論 2 354