Retrofit2+rxjava2源碼解析(三):兩者結(jié)合解析

我們在前面花了大量的筆墨講了下面兩篇文章:

主要是為了理清楚retrofit2和rxjava2的工作原理為這一篇兩者結(jié)合使用做鋪墊


一逻悠、這里我們先來看看兩者是怎么結(jié)合使用的(這里依然以登錄接口為例),與第一篇類似依然是三個步驟:

1.定義一個登錄接口

public interface APIFunction {
    /**
     * 登錄請求
     * @param map 請求參數(shù)
     * @return
     */
    @POST(HttpConfig.REQUEST_LOGIN)
    @Headers("Content-Type:application/vnd.api+json")
    Observable<ResponseBean<LoginBean>> login(@Body Map<String, Object> map);

}

2.初始化retrofit:

        //共通參數(shù)攔截器
        HeaderParamInterceptor commonParamInterceptor = new HeaderParamInterceptor();

        // 初始化okhttp
        OkHttpClient client = new OkHttpClient.Builder()
                .addInterceptor(commonParamInterceptor)
                .build();

        // 初始化Retrofit
        mRetrofit = new Retrofit.Builder()
                .client(client)
                .baseUrl(HttpConfig.IP)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//添加rxjava適配器
                .addConverterFactory(GsonConverterFactory.create())//添加gson轉(zhuǎn)換器
                .build();


        // 初始化Service
        mApiFunction = mRetrofit.create(APIFunction.class);

3.進(jìn)行網(wǎng)絡(luò)請求操作:

            RetrofitFactory.getInstance().API().login(map)
                    .subscribeOn(Schedulers.io())//此處必須將網(wǎng)絡(luò)請求切到子線程上面去
                    .observeOn(AndroidSchedulers.mainThread())//UI操作切回到主線程
                    .subscribe(new Observer<ResponseBean<LoginBean>>() {
                        @Override
                        public void onSubscribe(Disposable d) {
                            //做網(wǎng)絡(luò)請求前的準(zhǔn)備工作
                        }

                        @Override
                        public void onNext(ResponseBean<LoginBean> loginBeanResponseBean) {
                            //網(wǎng)絡(luò)請求成功以后的處理
                        }

                        @Override
                        public void onError(Throwable e) {
                            //網(wǎng)絡(luò)請求失敗以后的處理
                        }

                        @Override
                        public void onComplete() {
                            //整個流程結(jié)束以后的處理
                        }
                    });

二弯囊、看了上面幾個步驟肾档,可能會有幾個疑問:

  • rxjava2為什么可以和retrofit2完美結(jié)合臊旭?
  • retrofit2的enqueue方法可以將網(wǎng)絡(luò)請求放到線程里面,然后回調(diào)的處理切回到主線程,為什么這里還要使用rxjava2切換線程的方法庐完?
  • 第三步訂閱以后是如何進(jìn)行網(wǎng)絡(luò)請求的舶治?
    先別急分井,看完下面的解析就能一目了然了。

三霉猛、那么我們一探究竟吧:

(關(guān)于retrofit2和rxjava2的原理這里就不多做介紹了尺锚,主要講解這兩者結(jié)合使用的地方)
1.我們第一步里面將將接口返回對象改成了Observable,這樣就可以直接使用rxjava2的操作符以及訂閱方法了
2.第二個問題的話我們需要看第二步里面的一個操作:

.addCallAdapterFactory(RxJava2CallAdapterFactory.create())//添加rxjava適配器

通過第一篇文章我們知道這里添加的是一個適配器惜浅,主要用于ServiceMethod.adapt使用:

  T adapt(Call<R> call) {
    return callAdapter.adapt(call);
  }

這里的callAdapter就是上面配置的RxJava2CallAdapter瘫辩。所以接下來看看RxJava2CallAdapter的代碼吧

final class RxJava2CallAdapter<R> implements CallAdapter<R, Object> {
 ...代碼省略...

  @Override public Object adapt(Call<R> call) {
    Observable<Response<R>> responseObservable = isAsync
        ? new CallEnqueueObservable<>(call)
        : new CallExecuteObservable<>(call);

    Observable<?> observable;
    if (isResult) {
      observable = new ResultObservable<>(responseObservable);
    } else if (isBody) {
      observable = new BodyObservable<>(responseObservable);
    } else {
      observable = responseObservable;
    }

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

    if (isFlowable) {
      return observable.toFlowable(BackpressureStrategy.LATEST);
    }
    if (isSingle) {
      return observable.singleOrError();
    }
    if (isMaybe) {
      return observable.singleElement();
    }
    if (isCompletable) {
      return observable.ignoreElements();
    }
    return observable;
  }
}
public final class RxJava2CallAdapterFactory extends CallAdapter.Factory {
  /**
   * Returns an instance which creates synchronous observables that do not operate on any scheduler
   * by default.
   */
  public static RxJava2CallAdapterFactory create() {
    return new RxJava2CallAdapterFactory(null, false);
  }
  ...代碼省略...
  private final @Nullable Scheduler scheduler;
  private final boolean isAsync;

  private RxJava2CallAdapterFactory(@Nullable Scheduler scheduler, boolean isAsync) {
    this.scheduler = scheduler;
    this.isAsync = isAsync;
  }
  ...代碼省略...
}

因為在添加RxJava2CallAdapter的時候,調(diào)用的是RxJava2CallAdapterFactory.create()方法坛悉,所以上面代碼中isAsync是false伐厌,因此我們使用的CallExecuteObservable,看這個名字大致就能猜出這個是一個同步的操作方法裸影。當(dāng)然這種不能靠猜挣轨,還是得看看到底是不是這樣實現(xiàn)的

final class CallExecuteObservable<T> extends Observable<Response<T>> {
  ...代碼省略...

  @Override protected void subscribeActual(Observer<? super Response<T>> observer) {
    // Since Call is a one-shot type, clone it for each new observer.
    Call<T> call = originalCall.clone();
    ...代碼省略...

    boolean terminated = false;
    try {
      Response<T> response = call.execute();//執(zhí)行retrofit的execute方法
      ...代碼省略...
    } catch (Throwable t) {
      ...代碼省略...
    }
  }

  ...代碼省略...
}

從代碼中可以發(fā)現(xiàn)這里是執(zhí)行了call.exexute,這就跟我們第一篇文章講第三步講的網(wǎng)絡(luò)請求一樣了轩猩,只不過這里用了同步的操作方法卷扮。
因此我們這一篇文章的第三步里面需要用rxjava2將網(wǎng)絡(luò)請求操作放到子線程中
3.最后一個問題的話依然回到我們的CallExecuteObservable中來看看:

final class CallExecuteObservable<T> extends Observable<Response<T>> {
  private final Call<T> originalCall;

  CallExecuteObservable(Call<T> originalCall) {
    this.originalCall = originalCall;
  }

  @Override protected void subscribeActual(Observer<? super Response<T>> observer) {
    // Since Call is a one-shot type, clone it for each new observer.
    Call<T> call = originalCall.clone();
    CallDisposable disposable = new CallDisposable(call);
    observer.onSubscribe(disposable);

    boolean terminated = false;
    try {
      Response<T> response = call.execute();
      if (!disposable.isDisposed()) {
        observer.onNext(response);
      }
      if (!disposable.isDisposed()) {
        terminated = true;
        observer.onComplete();
      }
    } catch (Throwable t) {
      Exceptions.throwIfFatal(t);
      if (terminated) {
        RxJavaPlugins.onError(t);
      } else if (!disposable.isDisposed()) {
        try {
          observer.onError(t);
        } catch (Throwable inner) {
          Exceptions.throwIfFatal(inner);
          RxJavaPlugins.onError(new CompositeException(t, inner));
        }
      }
    }
  }

  private static final class CallDisposable implements Disposable {
    private final Call<?> call;
    private volatile boolean disposed;

    CallDisposable(Call<?> call) {
      this.call = call;
    }

    @Override public void dispose() {
      disposed = true;
      call.cancel();
    }

    @Override public boolean isDisposed() {
      return disposed;
    }
  }
}

仿照這位博主的流程圖均践,做了個簡易的關(guān)于retrofit2+rxjava2的流程圖:

retrofit2+rxjava2流程圖 .png

我們知道subscribeActual這個方法是在各自的Observable的subscribe方法里面調(diào)用的晤锹,所以在第三步的subscribe方法執(zhí)行以后,最終會執(zhí)行CallExecuteObservable的subscribeActual方法彤委。


總結(jié)

retrofit2+rxjava2結(jié)合使用的代碼量不多鞭铆,最主要的兩個類就是CallExecuteObservable和RxJava2CallAdapter。只要熟悉了前面兩篇文章的原理葫慎,那么這個基本上就是小意思衔彻。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末薇宠,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子艰额,更是在濱河造成了極大的恐慌澄港,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柄沮,死亡現(xiàn)場離奇詭異回梧,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)祖搓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進(jìn)店門狱意,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人拯欧,你說我怎么就攤上這事详囤。” “怎么了镐作?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵藏姐,是天一觀的道長。 經(jīng)常有香客問我该贾,道長羔杨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任杨蛋,我火速辦了婚禮兜材,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘逞力。我一直安慰自己曙寡,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布掏击。 她就那樣靜靜地躺著卵皂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪砚亭。 梳的紋絲不亂的頭發(fā)上灯变,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天,我揣著相機(jī)與錄音捅膘,去河邊找鬼添祸。 笑死,一個胖子當(dāng)著我的面吹牛寻仗,可吹牛的內(nèi)容都是我干的刃泌。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼耙替!你這毒婦竟也來了亚侠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤俗扇,失蹤者是張志新(化名)和其女友劉穎硝烂,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體铜幽,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡滞谢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了除抛。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狮杨。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖到忽,靈堂內(nèi)的尸體忽然破棺而出橄教,到底是詐尸還是另有隱情,我是刑警寧澤喘漏,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布颤陶,位于F島的核電站,受9級特大地震影響陷遮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜垦江,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一帽馋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧比吭,春花似錦绽族、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至赏表,卻和暖如春检诗,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瓢剿。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工逢慌, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人间狂。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓攻泼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子忙菠,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,527評論 2 349

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

  • 用兩張圖告訴你何鸡,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 12,699評論 2 59
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,777評論 25 707
  • 今日,與母親通電話時氢惋,她并未曾提起她身體狀況不適的話題洞翩。因她需要去忙點事電話給了小侄女,大寶貝才說今天跟奶奶去了哪...
    趙家小小姐閱讀 114評論 0 0
  • 2017年10月23日周一身修家和 美麗中國李瓊 種子踐行日記 第 62 天 ??服務(wù)眾生:分享《戴東說》到家...
    江南木子閱讀 333評論 0 0
  • 閱讀時間:2015.9.25/2016.4.2 寫在前面 第一次接觸這本書有點激動焰望,一天時間讀完了part 01和...
    Mia1515閱讀 1,198評論 0 3