【譯】使用RxJava實(shí)現(xiàn)延遲訂閱

我越來越喜歡把RxJava的defer()操作符作為一個工具來使用,以確保Observable代碼在被訂閱后才執(zhí)行(而不是創(chuàng)建后立即執(zhí)行)。我之前寫過一些有關(guān)defer()的代碼袁滥,但是惜犀,現(xiàn)在我想做更詳細(xì)的描述不从。

假設(shè)藻丢,有個數(shù)據(jù)類:

public class SomeType {  
private String value;

public void setValue(String value) {
  this.value = value;
}

public Observable<String> valueObservable() {
  return Observable.just(value);
}
}

這段代碼在運(yùn)行后會打印出什么呢把曼?

SomeType instance = new SomeType();  
Observable<String> value = instance.valueObservable();  
instance.setValue("Some Value");  
value.subscribe(System.out::println);  

如果你認(rèn)為會打印出“Some Value”杨帽,那就錯了。而實(shí)際打印結(jié)果是“null”祝迂。因?yàn)樵谡{(diào)用Observable.just()的時候睦尽,value已經(jīng)初始化了。

just()型雳,from()這類能夠創(chuàng)建Observable的操作符(譯者注:創(chuàng)建Observable的操作符)在創(chuàng)建之初当凡,就已經(jīng)存儲了對象的值,而不被訂閱的時候纠俭。這種情況沿量,顯然不是預(yù)期表現(xiàn),我想要的valueObservable()是無論什么時候請求冤荆,都能夠表現(xiàn)為當(dāng)前值朴则。

自助

一個解決辦法就是使用Observable.create(),因?yàn)樗试S為每個訂閱者精確控制事件的發(fā)送钓简。

public Observable<String> valueObservable() {
  return Observable.create(new Observable.OnSubscribe<String>() {
    @Override public void call(Subscriber<? super String> subscriber) {

      subscriber.onNext(value);
      subscriber.onCompleted();
    }
  });
}

現(xiàn)在乌妒,valueObservable()將在訂閱的時候發(fā)送當(dāng)前值(事件)。它除了在訂閱的時候才獲取value(而不是創(chuàng)建的時候)之外外邓,看起來和Observable.just()所做的沒什么兩樣撤蚊。

現(xiàn)在唯一的問題是,自從閱讀Dávid Karnok的解讀操作符系列文章后(譯者注:簡直不能更優(yōu)秀损话,一定要看)侦啸,我一直小心翼翼的編寫著自定義的操作符(譯者注:原著的意思是指,自定義操作符內(nèi)部處理方式丧枪,如上面代碼中的subscriber.onNext(value)等)光涂。通過閱讀該系列,我發(fā)現(xiàn)很難寫出正確的操作符拧烦。來看看這篇文章忘闻,Observable.just()為了支持背壓(譯者注:例如Observable.zip()操作符)和退訂是如何做出改變的。

當(dāng)然屎篱,上面那段代碼是能正確運(yùn)行的服赎,至少現(xiàn)在看來它是OK噠,但是隨著RxJava版本的不斷迭代交播,鬼知道以后能不能重虑。而且我也不知道類似背壓和退訂等操作能否安全的向下兼容。更何況秦士,我又不是操作符開發(fā)專家缺厉。所以,我試著避免自定義操作符,除非萬不得已提针。

簡單粗暴

這里有一種不需要自定義操作符的實(shí)現(xiàn)方式:

public Observable<String> valueObservable() {
  return Observable.defer(new Func0<Observable<String>>() {
    @Override public Observable<String> call() {
      return Observable.just(value);
    }
  });
}

我所做的就是用defer()操作符封裝原始代碼命爬,但現(xiàn)在的表現(xiàn)正是我想要的。defer()中的代碼直到被訂閱才會執(zhí)行辐脖。我們只需要在請求數(shù)據(jù)的時候調(diào)用Observable.just()就哦了饲宛。

我更喜歡這個解決方案的原因:

  1. Observable.create()更簡單,不再需要手動調(diào)用onCompleted()嗜价。

  2. 使用內(nèi)置操作符艇抠,這種方式(可能)更得到官方的肯定。

使用defer()操作符的唯一缺點(diǎn)就是久锥,每次訂閱都會創(chuàng)建一個新的Observable對象家淤。create()操作符則為每一個訂閱者都使用同一個函數(shù),所以瑟由,后者效率更高絮重。一如既往地,如果有必要可以親測性能或者嘗試優(yōu)化歹苦。

深入

上面代碼僅僅是為講解所用青伤,但是,切換到實(shí)際生產(chǎn)中殴瘦,我們需要用BehaviorSubject替換所有代碼潮模。讓我們來看一些更復(fù)雜的東西。

假設(shè)需要一個方法痴施,首先將數(shù)據(jù)寫進(jìn)磁盤,然后再作為結(jié)果返回究流。這是一種用defer()操作符的實(shí)現(xiàn):

public Observable<SomeType> createSomeType(final String value) {
  return Observable.defer(new Func0<Observable<SomeType>>() {
    @Override public Observable<SomeType> call() {

      SomeType someType = new SomeType();
      someType.setValue(value);

      try {
        db.writeToDisk(someType);
      } catch (IOException e) {
        return Observable.error(e);
      }

      return Observable.just(someType);
    }
  });
}

這個例子稍微復(fù)雜一些辣吃,將數(shù)據(jù)寫進(jìn)磁盤的同時如果拋出異常并捕獲,則立即調(diào)用onError芬探,基本的思路是相同的神得,那就是:在訂閱發(fā)生之前,不希望執(zhí)行任何代碼偷仿。

其實(shí)哩簿,有很多方式可以解決上面的問題,雖然使用defer()操作符只是其中之一酝静,但是节榜,使用起來真的很方便。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末别智,一起剝皮案震驚了整個濱河市宗苍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖讳窟,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件让歼,死亡現(xiàn)場離奇詭異,居然都是意外死亡丽啡,警方通過查閱死者的電腦和手機(jī)谋右,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來补箍,“玉大人改执,你說我怎么就攤上這事×笥瑁” “怎么了天梧?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長霞丧。 經(jīng)常有香客問我呢岗,道長,這世上最難降的妖魔是什么蛹尝? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任后豫,我火速辦了婚禮,結(jié)果婚禮上突那,老公的妹妹穿的比我還像新娘挫酿。我一直安慰自己,他們只是感情好愕难,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布早龟。 她就那樣靜靜地躺著,像睡著了一般猫缭。 火紅的嫁衣襯著肌膚如雪葱弟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天猜丹,我揣著相機(jī)與錄音芝加,去河邊找鬼。 笑死射窒,一個胖子當(dāng)著我的面吹牛藏杖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播脉顿,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蝌麸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了弊予?” 一聲冷哼從身側(cè)響起祥楣,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后误褪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體责鳍,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年兽间,在試婚紗的時候發(fā)現(xiàn)自己被綠了历葛。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡嘀略,死狀恐怖恤溶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情帜羊,我是刑警寧澤咒程,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站讼育,受9級特大地震影響帐姻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜奶段,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一饥瓷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧痹籍,春花似錦呢铆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至线定,卻和暖如春逆航,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背渔肩。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拇惋,地道東北人周偎。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像撑帖,于是被迫代替她去往敵國和親蓉坎。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評論 2 354

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