2016-06-05 8 views
0

ich eine Situation haben, in dem durch ein Item Objekt holen, einer der drei Dinge passieren sollte:Zusammenführen von Daten aus verschiedenen Observablen und verschiedene Fetching-Strategien wählen, je nach Datenverfügbarkeit

  • Falls das Produkt nicht im Cache vorhanden (aka ist null), laden Sie dann die Daten von api1 und api2, führen Sie die Daten zusammen und geben Sie Observable zurück.
  • Wenn das Element im Cache vorhanden ist, aber ein gewisser Teil davon fehlt, Ladedaten aus api2 und verschmilzt sie mit den bereits vorhandenen Daten im Cache
  • , wenn die gesamten Daten im Cache verfügbar sind, einfach Gib es zurück.

Bisher ist dies das Beste, was ich geschafft haben, zu kommen mit:

val cacheObservable = cache.fetchItem(itemId); 
val api1Observable = api1.fetchItem(itemId); 
val api2Observable = api2.fetchItem(itemId); 

val resultObservable = cacheObservable!!.flatMap { item: Item? -> 
    if (item == null) { 
     /* Get the item data, and the full text separately, then combine them */ 
     Observable.zip(api1Observable, api2Observable, { itemData, itemText -> 
      itemData.apply { text = itemText } 
     }); 
    } else if (item.text.isNullOrEmpty()) { 
     /* Get the full text only, then add it to the already cached version */ 
     cacheObservable.zipWith(api2Observable, { cachedItem, itemText -> cachedItem.apply { text = itemText; } }); 
    } else { 
     /* if the data and the full text are provided, simply return */ 
     Observable.just(item); 
    } 
}.doOnNext { item -> cache.saveOrUpdateItem(item); } 

return resultObservable; 

Das OK arbeitet, so weit, aber ich habe mich schon gefragt, wenn es eine deklarative Weg ist, den gleichen Effekt erzielen. Vorschläge sind willkommen.

+0

Ihre '' 'fetchItem''' Funktion kann einen Fehler zurück, statt' '' null''', so können Sie die Fehlerbehandlung Operatoren anstelle der Prüfung für null verwenden. – erkangur

Antwort

0

Ich weiß nicht Kotlin Syntax, aber hier ist ein Java-Beispiel, das Sie übersetzen können. Es erfordert cache.fetchItem(itemId) abzuschließen, anstatt eine null zu senden, wenn sich das Element nicht im Cache befindet.

Wenn cacheFetch ein Element ausgibt, stellt flatMap() sicher, dass das Element den Text enthält, und ruft es bei Bedarf aus dem Netzwerk ab.

Wenn nichts im Cache ist, wird fullFetch es aus dem Netzwerk abrufen.

concatWith(fullFetch).take(1) wird sichergestellt, dass fullFetch nur abonniert wird, wenn nichts im Cache ist.

Das Objekt wird nur im Cache gespeichert, wenn es aktualisiert wurde.

Observable<Item> cacheFetch = cache.fetchItem(itemId); 
Observable<Item> fullFetch = 
    Observable 
    .zip(
     api1.fetchItem(itemId), 
     api2.fetchItem(itemId), 
     (item, itemText) -> { 
      item.text = itemText; 
      return item; 
     }) 
    .doOnNext(cache::saveOrUpdateItem); 

Observable<Item> resultObservable = 
    cacheFetch 
    .flatMap(item -> { 
     if (item.text != null && !item.text.isEmpty()) { 
     return Observable.just(item); 
     } 
     return api2 
     .fetchItem(itemId) 
     .map(itemText -> { 
      item.text = itemText; 
      return item; 
     }) 
     .doOnNext(cache::saveOrUpdateItem); 
    }) 
    .concatWith(fullFetch) 
    .take(1); 
    }