RxJava入門與提高-Subject篇(2)

前言

歡迎繼續(xù)收看《RxJava入門與提高》砂吞,上周出了第一篇 RxJava入門與提高(1)
本文主要給大家補(bǔ)充一下上一篇遺留的Subject知識喧半,沒看過上一篇的同學(xué)惧磺、忘了上一章寫什么的同學(xué)、還有其他同學(xué)赏寇,RxJava入門與提高(1)吉嫩。溫習(xí)一遍,俗話說嗅定,“書讀百遍自娩,奇異自見”,看多一遍是一遍渠退,多多益善嘛忙迁。溫習(xí)完的,請回來繼續(xù)聽講碎乃。


Subject

關(guān)于Subject姊扔,官方文檔的解釋是這樣的:Subject可以看成是一個(gè)橋梁或者代理,在某些ReactiveX實(shí)現(xiàn)中(如RxJava)梅誓,它同時(shí)充當(dāng)了Observer和Observable的角色旱眯。因?yàn)樗且粋€(gè)Observer,它可以訂閱一個(gè)或多個(gè)Observable;又因?yàn)樗且粋€(gè)Observable删豺,它可以轉(zhuǎn)發(fā)它收到(Observe)的數(shù)據(jù),也可以發(fā)射新的數(shù)據(jù)愧怜。從官方解釋中呀页,我提取出三個(gè)要點(diǎn):

  1. 它可以充當(dāng)Observable;

  2. 它可以充當(dāng)Observer拥坛;

  3. 它是Observable和Observer之間的橋梁蓬蝶;

接下來對這三個(gè)要點(diǎn)解釋一下,但在解釋之前猜惋,要先介紹一下Subject的種類丸氛, Subject是一個(gè)抽象類,不能通過new來實(shí)例化Subject著摔,所以Subject有四個(gè)實(shí)現(xiàn)類缓窜,分別為AsyncSubjectBehaviorSubject谍咆、PublishSubjectReplaySubject禾锤,每個(gè)實(shí)現(xiàn)類都有特定的“技能”,下面結(jié)合代碼來介紹一下它們各自的“技能”摹察。注意恩掷,所有的實(shí)現(xiàn)類都由create()方法實(shí)例化,無需new,所有的實(shí)現(xiàn)類調(diào)用onCompleted()onError(),它的Observer將不再接收數(shù)據(jù)供嚎;


Subject的分類解析

  • AsyncSubject
    Observer會接收AsyncSubject的``onComplete()`之前的最后一個(gè)數(shù)據(jù)黄娘,如果因異常而終止,AsyncSubject將不會釋放任何數(shù)據(jù)克滴,但是會向Observer傳遞一個(gè)異常通知逼争。示例代碼如下:

          AsyncSubject<String> asyncSubject = AsyncSubject.create();
          asyncSubject.onNext("asyncSubject1");
          asyncSubject.onNext("asyncSubject2");
          asyncSubject.onNext("asyncSubject3");  
          asyncSubject.onCompleted();
          asyncSubject.subscribe(new Observer<String>() {
              @Override
              public void onCompleted() {
    
                  LogUtil.log("asyncSubject onCompleted");  //輸出 asyncSubject onCompleted
              }
    
              @Override
              public void onError(Throwable e) {
    
                  LogUtil.log("asyncSubject onError");  //不輸出(異常才會輸出)
              }
    
              @Override
              public void onNext(String s) {
    
                  LogUtil.log("asyncSubject:"+s);  //輸出asyncSubject:asyncSubject3
              }
          });
    

    以上代碼,Observer只會接收asyncSubject的onCompleted()被調(diào)用前的最后一個(gè)數(shù)據(jù)偿曙,即“asyncSubject3”氮凝,如果不調(diào)用onCompleted(),Subscriber將不接收任何數(shù)據(jù)望忆。

  • BehaviorSubject
    Observer會接收到BehaviorSubject被訂閱之前的最后一個(gè)數(shù)據(jù)罩阵,再接收其他發(fā)射過來的數(shù)據(jù),如果BehaviorSubject被訂閱之前沒有發(fā)送任何數(shù)據(jù)启摄,則會發(fā)送一個(gè)默認(rèn)數(shù)據(jù)稿壁。(注意跟AsyncSubject的區(qū)別,AsyncSubject要手動(dòng)調(diào)用onCompleted()歉备,且它的Observer會接收到onCompleted()前發(fā)送的最后一個(gè)數(shù)據(jù)傅是,之后不會再接收數(shù)據(jù),而BehaviorSubject不需手動(dòng)調(diào)用onCompleted(),它的Observer接收的是BehaviorSubject被訂閱前發(fā)送的最后一個(gè)數(shù)據(jù)喧笔,兩個(gè)的分界點(diǎn)不一樣帽驯,且之后還會繼續(xù)接收數(shù)據(jù)。)示例代碼如下:

      BehaviorSubject<String> behaviorSubject = BehaviorSubject.create("default");
      behaviorSubject.onNext("behaviorSubject1");
      behaviorSubject.onNext("behaviorSubject2");
          behaviorSubject.subscribe(new Observer<String>() {
              @Override
              public void onCompleted() {
    
                  LogUtil.log("behaviorSubject:complete");
              }
    
              @Override
              public void onError(Throwable e) {
    
                  LogUtil.log("behaviorSubject:error");
              }
    
              @Override
              public void onNext(String s) {
    
                  LogUtil.log("behaviorSubject:"+s);
              }
          });
    
          behaviorSubject.onNext("behaviorSubject3");
          behaviorSubject.onNext("behaviorSubject4");
    

    以上代碼书闸,Observer會接收到behaviorSubject2尼变、behaviorSubject3、behaviorSubject4浆劲,如果在behaviorSubject.subscribe()之前不發(fā)送behaviorSubject1嫌术、behaviorSubject2,則Observer會先接收到default,再接收behaviorSubject3牌借、behaviorSubject4度气。

  • PublishSubject
    PublishSubject比較容易理解,相對比其他Subject常用膨报,它的Observer只會接收到PublishSubject被訂閱之后發(fā)送的數(shù)據(jù)磷籍。示例代碼如下:

      PublishSubject<String> publishSubject = PublishSubject.create();
      publishSubject.onNext("publishSubject1");
      publishSubject.onNext("publishSubject2");
      publishSubject.subscribe(new Observer<String>() {
              @Override
              public void onCompleted() {
    
              }
    
              @Override
              public void onError(Throwable e) {
    
              }
    
              @Override
              public void onNext(String s) {
                  LogUtil.log("publishSubject observer1:"+s);
              }
          });
      publishSubject.onNext("publishSubject3");
      publishSubject.onNext("publishSubject4");
    

    以上代碼,Observer只會接收到"behaviorSubject3"丙躏、"behaviorSubject4"择示。

  • ReplaySubject
    ReplaySubject會發(fā)射所有數(shù)據(jù)給觀察者,無論它們是何時(shí)訂閱的晒旅。也有其它版本的ReplaySubject栅盲,在重放緩存增長到一定大小的時(shí)候或過了一段時(shí)間后會丟棄舊的數(shù)據(jù)。示例代碼如下:

    ReplaySubject<String>replaySubject = ReplaySubject.create(); //創(chuàng)建默認(rèn)初始緩存容量大小為16的ReplaySubject废恋,當(dāng)數(shù)據(jù)條目超過16會重新分配內(nèi)存空間谈秫,使用這種方式,不論ReplaySubject何時(shí)被訂閱鱼鼓,Observer都能接收到數(shù)據(jù)
    //replaySubject = ReplaySubject.create(100);//創(chuàng)建指定初始緩存容量大小為100的ReplaySubject
    //replaySubject = ReplaySubject.createWithSize(2);//只緩存訂閱前最后發(fā)送的2條數(shù)據(jù) 
    //replaySubject=ReplaySubject.createWithTime(1,TimeUnit.SECONDS,Schedulers.computation());  //replaySubject被訂閱前的前1秒內(nèi)發(fā)送的數(shù)據(jù)才能被接收     
    replaySubject.onNext("replaySubject:pre1");
    replaySubject.onNext("replaySubject:pre2");
    replaySubject.onNext("replaySubject:pre3");
    replaySubject.subscribe(new Action1<String>() {
          @Override
          public void call(String s) {
                  LogUtil.log("replaySubject:" + s);
          }
      });
    replaySubject.onNext("replaySubject:after1");
    replaySubject.onNext("replaySubject:after2");
    

    以上代碼拟烫,由于情況比較多,注釋也已解釋的相當(dāng)清楚迄本,就不對輸出結(jié)果一一表述了硕淑,有疑問的自行copy代碼去測試一下。



Subject類型用作接受者(Observer)

至此嘉赎,四種Subject類型已經(jīng)介紹完畢置媳,上文說過,Subject類型可以用作數(shù)據(jù)源(Observable)公条,也可以用作接受源(Observer)拇囊,或者兩者之間的橋梁。介紹四種Subject類型靶橱,就是當(dāng)做數(shù)據(jù)源(Observable)來介紹的寥袭。這里不在舉例累贅路捧。

但是需要注意,如果你把 Subject 當(dāng)作一個(gè) Observer(接受者)使用传黄,不要從多個(gè)線程中調(diào)用它的onNext方法(包括其它的on系列方法)杰扫,這可能導(dǎo)致同時(shí)(非順序)調(diào)用,這會違反Observable協(xié)議尝江,給Subject的結(jié)果增加了不確定性涉波。

  • 要避免此類問題,官方提出了“串行化”炭序,你可以將 Subject 轉(zhuǎn)換為一個(gè) SerializedSubject 鉴扫,類似于這樣:(這個(gè)我沒試驗(yàn)過空繁,只是自己在資料中查到的方法)

    SerializedSubject<String, Integer> ser = new SerializedSubject(publishSubject);
    
  • 在實(shí)際開發(fā)中,用的多的是下邊這種橋梁轉(zhuǎn)發(fā)的方式袱吆。

    PublishSubject<String> publishSubject = PublishSubject.create();
    Observable.create(new Observable.OnSubscribe<String>() {
          @Override
          public void call(Subscriber<? super String> subscriber) {
    
              subscriber.onNext("as Observer"); 
              subscriber.onCompleted();
          }
    }).subscribe(publishSubject);
    

    有沒有發(fā)現(xiàn)問題相恃?publishSubject沒有重寫onNext()方法啊辜纲,在哪接收的數(shù)據(jù)?這就是前面說的“橋梁”的問題了拦耐,盡管把Subject作為Observer傳入subscribe()耕腾,但接收數(shù)據(jù)還是要通過Observer來接收,借用Subject來連接Observable和Observer杀糯,整體代碼如下:

    PublishSubject<String> publishSubject = PublishSubject.create();
       Observable.create(new Observable.OnSubscribe<String>() {
              @Override
              public void call(Subscriber<? super String> subscriber) {
    
                  subscriber.onNext("as Bridge");
                  subscriber.onCompleted();
              }
          }).subscribe(publishSubject);
    
          publishSubject.subscribe(new Observer<String>() {
              @Override
              public void onCompleted() {
    
              }
    
              @Override
              public void onError(Throwable e) {
    
              }
    
              @Override
              public void onNext(String s) {
    
                  LogUtil.log("subject:"+s); //接收到 as Bridge
              }
          });
    

    沒錯(cuò)扫俺,這很橋梁!


總結(jié)

關(guān)于Subject固翰,到此就介紹完了狼纬。也許你會跟我一樣困惑,為什么又要多個(gè)Subject出來骂际,除了有幾個(gè)特定功能之外疗琉,其他所有的一切,Observable和Observer也都有歉铝,而且寫法上也沒有原來的簡便盈简。確實(shí)如此,對于幾個(gè)特定功能太示,我也還想不到有什么應(yīng)用場景柠贤,至少我還沒發(fā)現(xiàn)有什么場景必須得用Subject來實(shí)現(xiàn)不可,那么問題又來了先匪,我為什么要花這么大篇幅來介紹Subject种吸,理由有三。其一呀非,既然官方推出Subject坚俗,必有其道理镜盯,還沒遇到不代表以后不會遇到,更不能代表你不會遇到這樣的應(yīng)用場景猖败;其二速缆,“一千個(gè)讀者有一千個(gè)哈姆雷特”,我所看到的并不是全部恩闻,也許你會發(fā)掘出更有意思的東西可不是艺糜?其三,我可不想當(dāng)你看完我所有關(guān)于RxJava的文章幢尚,自信已上手RxJava破停,當(dāng)有人跟你提起Subject的時(shí)候,你一臉茫然不知道Subject是什么東西尉剩,豈不哀哉真慢?所以呢,介紹一下Subject還是很有意義的理茎,最起碼學(xué)了比沒學(xué)好黑界,“養(yǎng)兵千日用兵一時(shí)”,知識不嫌多皂林,突然哪天就用上了呢朗鸠。對于Subject的理解,有異議的歡迎底下評論础倍,一起交流進(jìn)步烛占。下一篇文章,進(jìn)入RxJava操作符的使用講解著隆。

歡迎繼續(xù)收看:RxJava入門與提高-操作符篇(3)
作者:ZhangYushui
來源:簡書
著作權(quán)歸作者所有扰楼。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處美浦。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末弦赖,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子浦辨,更是在濱河造成了極大的恐慌蹬竖,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件流酬,死亡現(xiàn)場離奇詭異币厕,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)芽腾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門旦装,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人摊滔,你說我怎么就攤上這事阴绢〉昀郑” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵呻袭,是天一觀的道長眨八。 經(jīng)常有香客問我,道長左电,這世上最難降的妖魔是什么廉侧? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮篓足,結(jié)果婚禮上段誊,老公的妹妹穿的比我還像新娘。我一直安慰自己栈拖,他們只是感情好枕扫,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著辱魁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪诗鸭。 梳的紋絲不亂的頭發(fā)上染簇,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天,我揣著相機(jī)與錄音强岸,去河邊找鬼锻弓。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蝌箍,可吹牛的內(nèi)容都是我干的青灼。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼妓盲,長吁一口氣:“原來是場噩夢啊……” “哼杂拨!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起悯衬,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤弹沽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后筋粗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體策橘,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年娜亿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了丽已。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,144評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡买决,死狀恐怖沛婴,靈堂內(nèi)的尸體忽然破棺而出吼畏,到底是詐尸還是另有隱情,我是刑警寧澤瘸味,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布宫仗,位于F島的核電站,受9級特大地震影響旁仿,放射性物質(zhì)發(fā)生泄漏藕夫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一枯冈、第九天 我趴在偏房一處隱蔽的房頂上張望毅贮。 院中可真熱鬧,春花似錦尘奏、人聲如沸滩褥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瑰煎。三九已至,卻和暖如春俗孝,著一層夾襖步出監(jiān)牢的瞬間酒甸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工赋铝, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留插勤,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓革骨,卻偏偏與公主長得像农尖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子良哲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評論 2 355

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