Это очень популярный вопрос, на который могут быть разные ответы,
, но я изо всех сил пытаюсь решить его правильным способом.
Чего я хочу достичь:
- В случае отсутствия ошибок сначала выведите кэшированные данные из базы данных, а затем обновите их данными из сети, как только они будут получены.
- В случае ошибки на пульте, показать данные из базы данных, , но также понять, что произошла ошибка и отображаются «кэшированные результаты» (этопроблема в моем случае)
Во-первых, у меня есть 2 метода в хранилище, которые возвращают соответственно данные из сети и базы данных:
private fun getUsersFromRemote(): Single<List<User>>() =
remote.getUsers()
.flatMap {
// saving fetched data to database
db.userDao().insert(MakeDbMapper.mapFrom(it))
.andThen(Single.just(it))
}
private fun getUsersFromDatabase(): Flowable<List<User>>() =
db.userDao.getUsers()
.distincUntilChanged()
(пропустите здесь сопоставление сущностей для простоты))
И открытый метод выглядит так:
fun getUsers(): Flowable<List<User>> =
Flowable.mergeDelayError(
getUsersFromRemote()
.toFlowable(),
geUsersFromDb()
.filter { it.isNotEmpty() })
.distinctUntilChanged()
- В такой реализации onError не вызывается из-за того, что mergeDelayError ожидает завершения всех потоков. Очевидно, что поток базы данных не собирается делать это.
- В случае использования
Flowable.merge()
Кажется, он работает как нужно -> сначала я получаю данные из базы данных, а затем ошибку. Однако, похоже, что это не правильный путь, потому что возможно получить ошибку из удаленного источника данных, а не из базы данных. Это приведет к прекращению потока перед получением кэшированных данных. - Возможно, имеет смысл сделать 2 открытых метода в хранилище,
, таких как:
fun subscribeForUsers(): Flowable<List<User>> = db.usersDao.getUsers()
и
fun refreshUsersFromRemote(): Completable =
remote.getUsers()
.flatMapCompletable {
db.userDao().insert(it)
}
В таком сценарии refreshUsersFromRemote()
позволит мне обработать удаленную ошибку, а также поможет опубликовать обновленных пользователей в subscribeForUsers()
после добавления новых элементов в базу данных. .
Последний подход, кажется, работает для меня, но я не уверен, что он правильный.
В таком случае мне придется вызывать 2 метода из уровня Presentation, однако я бы хотелвызовите только один и инкапсулируйте всю логику объединения источников данных в репозитории.