源碼分析:Retrofit結合RxJava

研究了兩個小時缠劝,終于讓我明白了Retrofit和RxJava是如何結合在一起的,分享給大家骗灶。本文將會從源碼角度來看這兩個家伙是如何配合的惨恭。閱讀前請確保理解Retrofit源碼和RxJava的基本使用。

支持原創(chuàng)耙旦,轉載請注明出處。

類圖

Retrofit&RxJava.png

使用場景

//創(chuàng)建接口
public interface IShot {
    //返回一個Observable锉罐,數(shù)據(jù)類型是List<Shot>
    Observable<Response<List<Shot>>> getShot(@Query("page") int page);
}

//創(chuàng)建Retrofit
Retrofit  retrofit = new Retrofit.Builder()
                    .baseUrl(PeanutInfo.URL_BASE)
                    .addConverterFactory(GsonConverterFactory.create())//添加GsonConverter
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())//添加RxJavaCallAdapter
                    .build();
//創(chuàng)建代理對象
IShot server = retrofit.create(Shot.class);

//發(fā)送請求绕娘,返回Observable
Observable<Response<List<Shot>>> observable = server.getShot(1);
//傳入Subscribe,進行訂閱
observable.subscribe(new Subscribe....);

創(chuàng)建Observable

在創(chuàng)建Retrofit時我們添加了GsonConverter和RxJavaCallAdapter抖拦。我們回想下Retrofit源碼舷暮,在調用了代理對象的getShot方法后會調用MethodHandler的invoke方法:

  Object invoke(Object... args) {
    return callAdapter.adapt(
        new OkHttpCall<>(callFactory, requestFactory, args, responseConverter));
  }

這里的callAdpter是由RxJavaCallAdapterFactory返回的下面,因為我們指定了CallAdapterFactory為RxJavaCallAdapterFactory,我們看看RxJavaCallAdapterFactory的源碼沥割,這個類在retrofit2/adapter包下:

public final class RxJavaCallAdapterFactory extends CallAdapter.Factory

---------------------------------get方法---------------------------------------------
  @Override
  public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    Class<?> rawType = getRawType(returnType); //獲取范型類型机杜,這里是Response<List<Shot>>
    boolean isSingle = "rx.Single".equals(rawType.getCanonicalName());
    if (rawType != Observable.class && !isSingle) {
      return null;
    }
    if (!(returnType instanceof ParameterizedType)) {
      String name = isSingle ? "Single" : "Observable";
      throw new IllegalStateException(name + " return type must be parameterized"
          + " as " + name + "<Foo> or " + name + "<? extends Foo>");
    }

    CallAdapter<Observable<?>> callAdapter = getCallAdapter(returnType); //根據(jù)返回類型獲取CallAdapter
    if (isSingle) {
      // Add Single-converter wrapper from a separate class. This defers classloading such that
      // regular Observable operation can be leveraged without relying on this unstable RxJava API.
      return SingleHelper.makeSingle(callAdapter);
    }
    return callAdapter;
  }

這個方法里根據(jù)返回類型returnType獲取范型類型rawType,我們這里是Response<List<Shot>>似将,然后根據(jù)rawType獲取CallAdapter,我們接著看下getCallAdapter方法:

  private CallAdapter<Observable<?>> getCallAdapter(Type returnType) {
    Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
    Class<?> rawObservableType = getRawType(observableType);
    if (rawObservableType == Response.class) { //Response類型
      if (!(observableType instanceof ParameterizedType)) {
        throw new IllegalStateException("Response must be parameterized"
            + " as Response<Foo> or Response<? extends Foo>");
      }
      Type responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
      return new ResponseCallAdapter(responseType);   //返回ResponseCallAdapter
    }

    if (rawObservableType == Result.class) {
      if (!(observableType instanceof ParameterizedType)) {
        throw new IllegalStateException("Result must be parameterized"
            + " as Result<Foo> or Result<? extends Foo>");
      }
      Type responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
      return new ResultCallAdapter(responseType);  //返回ResultCallAdapter
    }

    return new SimpleCallAdapter(observableType); //返回SimpleCallAdapter
  }

該方法根據(jù)返回值的具體類型返回對應的CallAdapter玷氏,我們的類型是Response<List<Shot>>,對應Response類盏触,所以返回ResponseCallAdapter块饺,終于找到了CallAdapter類了。再來回顧下MethodHandler的invoke方法:

  Object invoke(Object... args) {
    return callAdapter.adapt(
        new OkHttpCall<>(callFactory, requestFactory, args, responseConverter));
  }

我們看下ResponseCallAdapter的adapt()方法:

static final class ResponseCallAdapter implements CallAdapter<Observable<?>> {
    private final Type responseType;

    ResponseCallAdapter(Type responseType) {
      this.responseType = responseType;
    }

    @Override public Type responseType() {
      return responseType;
    }

    @Override public <R> Observable<Response<R>> adapt(Call<R> call) {
      return Observable.create(new CallOnSubscribe<>(call)); //創(chuàng)建一個CallOnSubscribe诗宣,用這個CallOnSubscribe創(chuàng)建Observable想诅,并返回。
    }
  }

到這里終于創(chuàng)建好了Observable来破。我們看下CallOnSubscribe這個類:

  static final class CallOnSubscribe<T> implements Observable.OnSubscribe<Response<T>> {
    private final Call<T> originalCall;           //引用OkHttpCall

    CallOnSubscribe(Call<T> originalCall) {
      this.originalCall = originalCall;        //傳入的是OkHttpCall
    }

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

      subscriber.add(Subscriptions.create(new Action0() {
        @Override public void call() {  //訂閱時調用這個方法
          call.cancel();
        }
      }));

      try {
        Response<T> response = call.execute(); //執(zhí)行網絡請求
        if (!subscriber.isUnsubscribed()) {
          subscriber.onNext(response);        //將結果傳入subscriber.onNext
        }
      } catch (Throwable t) {
        Exceptions.throwIfFatal(t);
        if (!subscriber.isUnsubscribed()) {
          subscriber.onError(t);       //出現(xiàn)錯誤是調用 subscriber.onError
        }
        return;
      }

      if (!subscriber.isUnsubscribed()) {
        subscriber.onCompleted();
      }
    }
  }

CallOnSubscribe實現(xiàn)了OnSubscribe接口诅诱,內部引用了OkHttpCall,執(zhí)行真正的網絡請求娘荡。進行訂閱時會調用call方法驶沼,該方法調用OkHttpCall.execute獲取響應,傳遞給subscriber.onNext這樣就發(fā)生了一次訂閱回怜。到這里Retrofit和RxJava就完美結合了。

最后看下類圖玉雾,就更清楚了。


Retrofit&RxJava.png

總結

Retrofit添加了RxJavaCallAdapterFactory后垦缅,對應的callAdapter就是ResponseAdapter或SimpleCallAdapter類壁涎,他們的adapt方法返回一個Observable對象柏蘑,這個Observable內部引用了真正執(zhí)行網絡請求的OkHttpCall。

后面會將更多筆記整理成博客洽损,歡迎關注。
支持原創(chuàng)流码,轉載請注明出處。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末漫试,一起剝皮案震驚了整個濱河市驾荣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌播掷,老刑警劉巖撼班,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異件炉,居然都是意外死亡矮湘,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門宫静,熙熙樓的掌柜王于貴愁眉苦臉地迎上來券时,“玉大人,你說我怎么就攤上這事橘洞。” “怎么了炸枣?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長霍衫。 經常有香客問我,道長澄干,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任麸俘,我火速辦了婚禮从媚,結果婚禮上患整,老公的妹妹穿的比我還像新娘。我一直安慰自己并级,他們只是感情好,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布稻励。 她就那樣靜靜地躺著愈涩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪煤篙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天辑奈,我揣著相機與錄音鸠窗,去河邊找鬼胯究。 笑死,一個胖子當著我的面吹牛裕循,可吹牛的內容都是我干的净刮。 我是一名探鬼主播淹父,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼弹灭,長吁一口氣:“原來是場噩夢啊……” “哼揪垄!你這毒婦竟也來了逻翁?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤酷愧,失蹤者是張志新(化名)和其女友劉穎缠诅,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體管引,經...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡褥伴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年重慢,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片隅熙。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡核芽,死狀恐怖,靈堂內的尸體忽然破棺而出弯淘,到底是詐尸還是另有隱情吉懊,我是刑警寧澤假勿,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布态鳖,位于F島的核電站,受9級特大地震影響浸须,放射性物質發(fā)生泄漏邦泄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一顺囊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧诚亚,春花似錦、人聲如沸午乓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蒸其。三九已至,卻和暖如春颂暇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背耳鸯。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工县爬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留添谊,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓耳高,卻偏偏與公主長得像,于是被迫代替她去往敵國和親概荷。 傳聞我的和親對象是個殘疾皇子碌燕,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內容

  • 前言 在Android開發(fā)中修壕,網絡請求十分常用 而在Android網絡請求庫中,Retrofit是當下最熱的一個網...
    Carson帶你學安卓閱讀 70,616評論 48 393
  • Retrofit這個開源庫出來也有一定年頭了改鲫,記得之前還是在V1.0的版本的時候林束,之前在三月份也寫過一個Retro...
    lovejjfg閱讀 1,429評論 0 5
  • 安卓開發(fā)領域中壶冒,很多重要的問題都有很好的開源解決方案截歉,例如Square公司提供網絡請求 OkHttp , Retr...
    aaron688閱讀 1,903評論 1 20
  • 1 莫倩倩從大巴下來的時候瘪松,看到天空已經完全黑了下來,冷風吹過宵睦,讓她忍不住一抖,伸出手拉緊了大衣的領子壳嚎。 她拉著行...
    邵悅婷閱讀 4,465評論 48 51
  • 不知為何有時候我們總會對一些事烟馅,對一些人放在心上,說不上有多掛念郑趁,說不上有多關注刊驴。但它卻成為了你心里的一根隱隱作...
    不傷心不甘心閱讀 215評論 0 2