2014-12-01 2 views
13

Я ищу пример потока, который я пытаюсь реализовать с помощью RxJava.Запросы и кеширование RxJava

Предположим, я хочу показать список данных. Поток должен выглядеть примерно так:

  1. Прочитать кэш. Если он содержит данные, покажите его;
  2. Отправить запрос API к серверу:

    Если он вернулся данные, а затем кэшировать его и показать его.

    Если оно вернулось и ошибка, и не было кэшированных данных, тогда отобразите ошибку.

    Если он вернулся и ошибка, и там что-то было кешировано, тогда ничего не делайте.

Прямо сейчас у меня есть method that does something similar (с большим количеством вдохновения от Jake's u2020). Основное различие заключается в том, что он использует кэширование в памяти, что означает, что нет необходимости в отдельном Observable для чтения из кеша, и это можно сделать синхронно.

Я не знаю, как объединить два наблюдаемых (один для чтения из кеша, а другой для вызова API) и получить описанный выше поток.

Любые предложения?

+0

Похоже, вам нужна 'amb': https://github.com/ReactiveX/RxJava/wiki/Conditional-and-Boolean-Operators#amb – zsxwing

+0

@zsxwing вы могли бы привести пример?Я открыт для предложений, хотя я нашел ответ (что не идеально). –

+0

Я хотел бы оставить обработку кэша сетевым клиентом. Если вы используете HTTP, в ответе есть заголовок, который предназначен для указания клиенту, какой тип кеша должен быть реализован, как долго должен сохраняться объект ... Не говоря уже о том, что есть также возможность проверить, что ваш кеш по-прежнему действительны и при необходимости обновлять (код возврата 304). – njzk2

ответ

1

Вот мое решение:

readDataFromCache().defaultIfEmpty(null) 
     .flatMap(new Func1<Data, Observable<Data>>() { 

      @Override 
      public Observable<Data> call(final Data data) { 
       if (data == null) { 
        // no cache, show the data from network or throw an error 
        return apiCall(); 
       } else { 
        return Observable.concat(
          Observable.just(data), 
          // something cached, show the data from network or do nothing. 
          apiCall().onErrorResumeNext(Observable.<Data>empty())); 
       } 
      } 
     }); 

Я не добавить subscribeOn и observeOn, потому что я не уверен, что readDataFromCache() следует использовать ioScheduler или uiScheduler.

+0

Единственная проблема, с которой я столкнулся, - это когда 'readDataFromCache()' возвращает ошибку. 'onErrorResumeNext (Observable. empty())' перед добавлением 'defaultIfEmpty (null)' перед пропуском ошибки. –

2

Я думаю, что я решил свою проблему. Наблюдаемая цепочка выглядит так:

apiCall() 
     .map(data -> dataInMemory = data) 
     .onErrorResumeNext(t -> data == null ? 
       Observable.just(Data.empty()) : Observable.empty()) 
     .startWith(readDataFromCache().map(data -> dataInMemory = data)) 
     .subscribeOn(ioScheduler) 
     .observeOn(uiScheduler) 
     .subscribe(dataRequest); 

Главное в том, что если readDataFromCache() выдает ошибку, он будет вызывать onCompleted()onError() без вызова. Таким образом, это должно быть обычай Observable, которым вы можете управлять.

Data.empty() является заглушкой для моих данных - Subscriber должен относиться к ней как к ошибке.

dataInMemory является членом моего контроллера, который действует как кеш в памяти.


EDIT: решение не работает должным образом. Завершение одного варианта использования (см. Комментарий) не достигается.

EDIT 2: хорошо, решение делает работу должным образом после некоторой настройки. Исправление возвращало различные типы наблюдаемых в зависимости от состояния кэша в памяти. Вид грязный.

+0

Ну, мое решение не работает. Если 'readDataFromCache()' идет хорошо и показывает некоторые данные, а 'apiCall()' возвращает ошибку, он показывает ошибку. –

Смежные вопросы