Я пытаюсь реализовать поставщика, который ищет товары в memory
, disk
, network
, в этом порядке. Основная цель этого - избежать сетевых вызовов, если у меня есть правильный локальный кеш. Существует уловка, поскольку мои вызовы в сеть используют фильтры для получения элементов, я мог бы иметь 10 элементов из локального запроса, но все равно нужно перейти в сеть, потому что эти элементы поступают из другого сетевого вызова с различными параметрами запроса.Оператор RxJava для провайдера кэшированных товаров
Прямо сейчас я использую concat
с firstOrDefault
, проверяя, что список не пустой или пустой. Я внедрил способ проверить, действительно ли я уже вызвал сервер с конкретным запросом, и я использую его для возврата значения null при чтении с диска.
теперь мне нужно уточнить у поставщика, так что:
- излучает местные пункты
- пойти онлайн при необходимости
- излучает онлайн элементы
(Сейчас это останавливается в первом хорошем списке предметов).
Я пытаюсь использовать takeWhile
, используя метод, который возвращает true, если данные являются пустыми или пустыми, или если я еще не вызывал сервер для этого запроса. Проблема заключается в том, что takeWhile не выделяет элемент, если проверка для этого элемента ложна, то есть я не получу последний хороший товар (который также является лучшим).
Лучшее решение, о котором я могу думать, это оператор, который испускает элементы до тех пор, пока не появится какое-то условие, а затем отмените подписку на себя. Я не могу его найти.
EDIT: НЕКОТОРЫЙ КОД Решение 1) с помощью firstOrDefault
: не будет издавать местные предметы, если !DiskService.wasDownloaded()
, потому что DiskService
возвращения нулевой List<Item>
с !DiskService.wasDownloaded()
public Observable<List<Item>> items() {
List<Observable> obs = new ArrayList<>();
Observable<List<Item>> memoryObs = Observable.defer(this::getMemoryItems);
Observable<List<Item>> diskObs = Observable.defer(this::getDiskItems);
Observable<List<Item>> networkObs = Observable.defer(this::getNetworkItems);
Observable<List<Item>> concat = Observable.concat(memoryObs, diskObs, networkObs;
return concat.firstOrDefault(new ArrayList<>(), this::canAccept);
}
private boolean canAccept(List<Item> data) {
return data != null && data.size() > 0;
}
//Method in DiskService
public boolean wasDownloaded(){
return true if the query was performed on the server, false otherwise.
}
Solution 2) Использованием takeWhile
. Проблема с takeWhile является Observable, не будет излучать элемент, который не проверяет его состояние, то есть я не получу лучший список. Хакерное решение - отложить ложную проверку до следующего элемента, но таким образом сетевой запрос будет запущен, даже если это не необходимо. С помощью этого решения я использую TrustedItemList
что только содержит перечень и логическое, который говорит Наблюдаемая, если он может доверять непустой список элементов (всегда верно для memory
и network
, правда, если wasDownloaded()
для disk
)
public Observable<List<Item>> items() {
List<Observable> obs = new ArrayList<>();
Observable<TrustedItemList> memoryObs = Observable.defer(this::getMemoryItems);
Observable<TrustedItemList> diskObs = Observable.defer(this::getDiskItems);
Observable<TrustedItemList> networkObs = Observable.defer(this::getNetworkItems);
Observable<TrustedItemList> concat = Observable.concat(memoryObs, diskObs, networkObs;
return concat.takeWhile(this::shouldContinueSearching)
.filter(trustedItemList -> trustedItemList.items != null && !trustedItemList.items.isEmpty())
.map(trustedItemList -> trustedItemList.items);
}
private boolean shouldContinueSearching(TrustedPoiList data) {
return data == null || data.items == null || data.items.isEmpty() || !data.canTrustIfNotEmpty;
}
Я рекомендовал бы добавить немного коды для нас, чтобы получить контекст, потому что сейчас это выглядит несколько абстрактно и поощрение к предоставлению родового ответы, как использование 'combLatest()'. – AndroidEx
Я добавил некоторый «псевдо» код (не этот псевдо). Проблема с combLatest заключается в том, что сетевой запрос всегда срабатывает, чего я хочу избежать. –