RxJava2.0使用詳解(一)

一、前言

  • RxJava是什么呢?根據RxJavaGitHub上給出的描述
    RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java
    大致意思是:一個可以在JVM上使用的,是由異步的基于事件編寫的通過使用可觀察序列構成的一個庫。
    關鍵詞:異步,基于事件,可觀察序列

  • 之前只是了解了Rx1.x時候的源碼和使用方式,由于當時成員技術棧不統一,就沒有在產品中使用。現在隨著Rx的持續發熱,身為主程的我依然留著對rx的喜愛,故現決定引入rx。

  • 雖然有過使用rx的經歷,但是現在rx升級到了2.0的版本,變化幅度還是蠻大的,所以抱著從0開始的心態,從新學習Rx2.X的相關代碼及使用注意事項。

  • 本次學習歷程所定目標如下:
    1.初步了解RxJava2.X的使用流程
    2.探索Observable發送數據的流程
    3.明白Observer是如何接收數據的
    4.解析ObservableObserver的勾搭(如何關聯)過程
    5.探索RxJava線程切換的奧秘
    6.了解RxJava操作符的實現原理

  • 本次學習基于RxJava2.1.1版本的源碼

二、從Demo到原理

  //1、觀察者創建一個Observer
  Observer observer = new Observer() {
      @Override
    public void onSubscribe(@NonNull Disposable d) {
          Log.d(TAG, "onSubscribe");
      }

      @Override
    public void onNext(@NonNull String s) {
          Log.d(TAG, "onNext data is :" + s);

      }

      @Override
    public void onError(@NonNull Throwable e) {
          Log.d(TAG, "onError data is :" + e.toString());
      }

      @Override
    public void onComplete() {
          Log.d(TAG, "onComplete");
      }
  };

  Observable observable = Observable.create(new ObservableOnSubscribe() {
      @Override
    public void subscribe(@NonNull ObservableEmitter e) throws Exception {
          e.onNext("hello");
          e.onNext("world");
          e.onComplete();

      }
  });
  observable.subscribe(observer);
  • 結果輸出:

      onSubscribe
      onNext data is :hello
      onNext data is :world
      onComplete
    
  • 可以看到,Observer的onSubscribe是最先被調用的,這個用什么用呢?我們后面會講到。


  • OK,從哪開始入手呢?Observable.create,嗯,整個流程是從create開始的,那么我們就從源頭開始吧。先看一下create,他會煩的是一個observable對象,也就是被觀察的對象。create方法需要傳入一個ObservableOnSubscribe來創建,我們看下ObservableOnSubscribe是什么

      public interface ObservableOnSubscribe<T> {
          /**
       * Called for each Observer that subscribes. * @param e the safe emitter instance, never null
       * @throws Exception on error
       */  void subscribe(@NonNull ObservableEmitter<T> e) throws Exception;
      }
    
  • 該接口會接收一個ObservableEmitter的一個對象,然后通過該對象我們可以發送消息也可以安全地取消消息,我們繼續看ObservableEmitter這個借口類

      public interface ObservableEmitter<T> extends Emitter<T> {
    
            void setDisposable(@Nullable Disposable d);
    
            void setCancellable(@Nullable Cancellable c);
    
            boolean isDisposed();
    
            @NonNull
            ObservableEmitter<T> serialize();
    
             @Experimental
            boolean tryOnError(@NonNull Throwable t);
      }
    
  • ObservableEmitter是對Emitter的擴展,而擴展的方法證實RxJava2.0之后引入的,提供了可中途取消等新能力,我們繼續看Emitter

      public interface Emitter<T> {
    
             void onNext(@NonNull T value);
    
            void onError(@NonNull Throwable error);
    
            void onComplete();
      }
    
  • 里面的三個方法使用過rx的應該非常眼熟了??吹竭@里,我們只是了解了傳遞參數的數據結構,了解到的信息還是比較少的。我們繼續看下create內部做了什么操作呢?

      public static <T> Observable<T> create(ObservableOnSubscribe<T> source) {
          ObjectHelper.requireNonNull(source, "source is null");
          return RxJavaPlugins.onAssembly(new ObservableCreate<T>(source));
      }
    
  • RxJavaPlugins或許你會很陌生,其實我也很陌生,不過沒關系,我覺得后面會經常遇到RxJavaPlugins,熟悉它是必然的;

  • 可以看到我們傳入ObservableOnSubscribe被用來創建ObservableCreate,其實ObservableCreate就是Observable的一個實現類哦。

思路梳理

  • OK,到這里我們先梳理一下思路:
    1、Observable通過調用create創建一個Observable
    2、調用create時需要傳入一個ObservableOnSubscribe類型的實例參數
    3、最終傳入的ObservableOnSubscribe類型的實例參數作為ObservableCreate構造函數的參數傳入,一個Observable就此誕生了

-ObservableCreate又是個什么東東呢?我們分步來,先看ObservableCreate的兩個方法

  public final class ObservableCreate<T> extends Observable<T> {
      final ObservableOnSubscribe<T> source;

      public ObservableCreate(ObservableOnSubscribe<T> source) {
          this.source = source;
      }

      @Override
    protected void subscribeActual(Observer<?super T> observer) {
          CreateEmitter<T> parent = new CreateEmitter<T>(observer);
          observer.onSubscribe(parent);

          try {
              source.subscribe(parent);
          } catch (Throwable ex) {
              Exceptions.throwIfFatal(ex);
              parent.onError(ex);
          }
      }
  .....
  }
  • source:Observable.createc傳入的ObservableOnSubscribe實例

  • subscribeActual回調方法,它在調用Observable.subscribe時被調用,即與觀察者或則訂閱者發生聯系時觸發。subscribeActual也是實現我們主要邏輯的地方,我們來仔細分析下subscribeActual方法:
    1、首先subscribeActual傳入的參數為Observer類型,也就是我們subscribe時傳入的觀察者,到底是不是呢?后面會分析到。
    2、傳入的Observer會被包裝成一個CreateEmitter,CreateEmitter繼承了AtomicReference提供了原子級的控制能力。RxJava2.0提供的新特性與之息息相關哦,這個我們先給它來個關鍵標簽,后面再詳細分析。
    3、 觀察者(observer)調用自己的onSubscribe(parent);將包裝后的observer傳入。這個也是RxJava2.0的變化,真正的訂閱在source.subscribe(parent);這句代碼被執行后開始,而在此之前先調用了onSubscribe方法來提供RxJava2.0后引入的新能力(如中斷能力)。從這里我們也就知道了為何觀察者的onSubscribe最先被調用了。(被訂閱者說:我也很無辜,他自己調用了自己,我也控制不了╮(╯_╰)╭)
    4、被訂閱者或者說被觀察者(source)調用subscribe訂閱方法與觀察者發生聯系。這里進行了異常捕獲,如果subscribe拋出了未被捕獲的異常,則調用 parent.onError(ex);
    5、在執行subscribe時也就對應了我們demo中的

    public void subscribe(@NonNull ObservableEmitter e) throws Exception {
        e.onNext("hello");
        e.onNext("world");
        e.onComplete();
    
    }
    
  • Ok,看來subscribeActual這個回調確實很重要,前面我們也說了subscribeActual回調方法在Observable.subscribe被調用時執行的,真的像我說的一樣么?萬一我看走眼了

      @SchedulerSupport(SchedulerSupport.NONE)
      @Override
      public final void subscribe(Observersuper T> observer) {
          ObjectHelper.requireNonNull(observer, "observer is null");
          try {
              observer = RxJavaPlugins.onSubscribe(this, observer);
    
              ObjectHelper.requireNonNull(observer, "Plugin returned null Observer");
    
              subscribeActual(observer);
          } catch (NullPointerException e) { // NOPMD
        throw e;
          } catch (Throwable e) {
              Exceptions.throwIfFatal(e);
              // can't call onError because no way to know if a Disposable has been set or not
       // can't call onSubscribe because the call might have set a Subscription already  RxJavaPlugins.onError(e);
    
              NullPointerException npe = new NullPointerException("Actually not, but can't throw other exceptions due to RS");
              npe.initCause(e);
              throw npe;
          }
      }
    
  • OK,代碼不多,可以看到RxJavaPlugins.onSubscribe(this, observer);,我們RxJava2.0中的Hook能力就是來自這里了。然后繼續看下面subscribeActual(observer);被調用了。

思路梳理

1、傳入的ObservableOnSubscribe最終被用來創建成ObservableOnSubscribe
2、ObservableOnSubscribe持有我們的被觀察者對象以及訂閱時所觸發的回調subscribeActual
3、在subscribeActual實現了我們的主要邏輯,包括observer.onSubscribe(parent);,source.subscribe(parent);,parent.onError(ex);的調用
4、在Observable的subscribe被調用時開始執行事件分發流程。


三、總結

  • 本次,我們只是實現了我們6個目標中的一小部分,通過本次,我們對于RxJava的神秘感是否又消失了一點呢?
  • 后面的Rx系列文章將會循序漸進,逐步分析RxJava的各個神秘點。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,401評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,011評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,263評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,543評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,323評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,874評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,968評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,095評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,605評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,551評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,720評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,242評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,961評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,358評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,612評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,330評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,690評論 2 370

推薦閱讀更多精彩內容