Fusionar datos de diferentes Observables y elegir diferentes estrategias de búsqueda, según la disponibilidad de datos

Tengo una situación en la que, al search un object Item , debe ocurrir una de estas tres cosas:

  • Si el elemento no está presente en la memory caching (también conocido como nulo), cargue datos de api1 y api2 , api2 los datos y devuelva un Observable .
  • Si el elemento está presente en la memory caching, pero falta una determinada parte, cargue datos de api2 y api2 con los datos ya disponibles en la memory caching.
  • si la información completa está disponible en la memory caching, simplemente devuelvala.

Hasta el momento, esto es lo mejor que he logrado encontrar:

 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; 

Esto funciona bien, hasta ahora, pero me he estado preguntando, si hay una forma más declarativa de lograr el mismo efecto. Sugerencias son bienvenidas.

No conozco la syntax de Kotlin, pero aquí hay un ejemplo de Java que puedes traducir. Requiere cache.fetchItem(itemId) para completar en lugar de emitir un null cuando el elemento no está en la caching.

Si cacheFetch emite un elemento, el flatMap() asegurará que el elemento tenga el text y lo busque de la networking si es necesario.

Si no hay nada en la memory caching, fullFetch lo obtendrá de la networking.

concatWith(fullFetch).take(1) asegurará que fullFetch solo esté suscrito si no hay nada en caching.

El elemento solo se guarda en la memory caching si se actualizó.

 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); } 
  • Kotlin: Cómo convertir la testing que usa Thread.sleep a RxJava TestScheduler
  • ¿Debo cancelar la suscripción cuando uso rxbinding?
  • Kotlin - ¿Cómo crear una function de alias de RxJava flatmap ()?
  • El método de callback a menudo para reenviar el evento a Observable?
  • ¿Alguna diferencia entre "Subject.asObservable ()" y el tema en sí "Subject"?
  • No se pudo deducir Kotlin y RxJava
  • RxJava: cómo devolver el tipo correcto de nulo
  • Aplicando transformación a cada elemento en Single <List <T >>
  • ¿Cómo hacer un grupo? ¿Por qué coleccionar usando RxJava y Kotlin?
  • Cómo usar la class ContextWrapper con subscribeWith
  • Adaptador personalizado de Moshi con RxAndroid & Retrofit & Kotlin