Intereting Posts
Запись метаданных EXIF ​​на изображения в Android Что вызывает MotionEvent.ACTION_CANCEL в Android? ClassCastException при попытке сделать readParcelable в настраиваемом массиве объектов Установка onClickListner для права Drawable EditText Как наложить изображение или изображение поверх снимка, снятого камерой ADB не может найти Nexus 7 в Mac OS X Mavericks Динамическое добавление представлений в цикле for приводит к беспорядочному позиционированию – Android Знак градуса (как в градусах Цельсия / Фаренгейта) в TextView Является ли приложение Android для удаления батареи? Android-кодировка Android по умолчанию при отправке http post / put – Проблемы со специальными символами EditText android: подсказка не исчезает onFocus Как заставить клавиатуру с цифрами на мобильном сайте в Android Производительность прокрутки RecyclerView Как запустить широковещательный приемник при включении / выключении gps? Как удалить тень над панелью приложений?

Сетевые запросы RxJava и кэширование

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

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

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

    Если он вернет данные, то кешируйте их и покажите.

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

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

Сейчас у меня есть метод, который делает что-то подобное (с большим вдохновением от u2020 от Jake ). Основное различие заключается в том, что он использует кэширование в памяти, что означает, что нет необходимости в отдельном Observable для чтения из кеша, и это можно сделать синхронно.

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

Какие-либо предложения?

Solutions Collecting From Web of "Сетевые запросы RxJava и кэширование"

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

 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 .

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

 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: хорошо, решение работает правильно после некоторой настройки. Исправление возвращало различные типы наблюдаемых в зависимости от состояния кэша в памяти. Вид грязный.