天天看點

使用RxJava從多個資料源擷取資料

試想,需要一些動态資料的時候,隻要每次都請求網絡就可以了。但是,更有效率的做法是,把聯網得到的資料,緩存到磁盤或記憶體。

具體的說,計劃如下:

偶爾的聯網操作,隻為擷取最新資料。

盡可能快的讀取到資料(通過擷取之前緩存的網絡資料)。

使用RxJava從多個資料源擷取資料

基本模式

為每一個資料源(網絡,磁盤和記憶體)建立observable,使用concat()和first()操作符,構造一個簡單的實作方式。

// our sources (left as an exercise for the reader) 

observable memory = ...;  

observable disk = ...;  

observable network = ...; 

// retrieve the first source with data 

observable source = observable  

  .concat(memory, disk, network) 

  .first(); 

observablememory = ...;   

observabledisk = ...;   

observablenetwork = ...; 

observablesource = observable   

這種模式的關鍵在于concat()操作符隻有需要資料的時候才會訂閱所有的observable資料源。由于first()操作符會較早的停止檢

索隊列,是以,如果存在緩存資料,就沒有必要通路較慢的資料源。

也就是說,如果memory傳回結果,就不必擔心disk和network會被通路。相反地,如果記憶體和磁盤都沒有資料,才執行網絡請求。

注意concat()所持有的observable資料源,是按照一個接一個的順序被檢索的。

持久化資料

很明顯,下一步是緩存資料。如果不把網絡請求後的結果緩存到磁盤,磁盤通路後的結果緩存到記憶體,那麼這根本不就不叫緩存。接下來要寫的代碼就是,網絡資料的持久化操作。

我的解決方案是,讓每個資料源在發送完事件後,都儲存或者緩存資料。

observable networkwithsave = network.doonnext(new action1() { 

@override public void call(data data) { 

savetodisk(data); 

cacheinmemory(data); 

}); 

observable diskwithcache = disk.doonnext(new action1() { 

  cacheinmemory(data); 

 observablenetworkwithsave = network.doonnext(new action1() { 

@overridepublic void call(datadata) { 

observablediskwithcache = disk.doonnext(new action1() { 

現在,如果你使用networkwithsave和diskwithcache,資料将會在加載後自動儲存。

(這個政策的另一個優勢在于networkwithsave和diskwithcache可以在任何地方被使用,不局限于我們的多資料模式下。)

陳舊的資料

不幸的,現在我們儲存資料的那些代碼,執行的有點過頭了。無論資料是否過時,它總是傳回相同的資料。我們希望做到,偶爾連接配接伺服器抓取最新的資料。

解決方法在于,使用first()操作符進行過濾。就是設定它拒絕接收毫無價值的資料。

observable source = observable 

    .concat(memory, diskwithcache, networkwithsave) 

    .first(new func1() { 

      @override public boolean call(data data) { 

        return data.isuptodate(); 

      } 

    }); 

observablesource = observable 

      @overridepublic boolean call(datadata) { 

現在,我們隻需要發送被斷定為最新資料的事件就ok了。是以,隻要有一個資料源的資料過期,就繼續檢索下一個資料源,直到找到最新資料為止。

first()和takefirst()操作符的比較

兩種調用方式的差別在于,如果所有資料源的資料均過期,沒有任何的有效資料作為事件發送,first()會抛出

nosuchelementexception異常(譯者注:first()操作符均return

false),而takefirst()操作符則直接調用完成操作,不會抛出任何異常。

使用哪個操作符,完全取決于是否需要明确處理缺失的資料。

代碼示例

來源:51cto

繼續閱讀