Я пытаюсь реализовать полный репозиторий, используя новую поддержку потока в комнате и поддержку сопрограмм дооснащения. У меня возникают проблемы, решения которых я не могу найти.
Итак, сначала давайте расскажем, чего я добился. Это мой класс ViewModel:
class InvViewModel : ViewModel() {
val repo = Repository()
val flow = flow {
emit(Lce.Loading())
val result = repo.updateInv()
repo.getInv().collect { inv ->
result?.let { exception ->
emit(Lce.Error<List<Inv>>(inv, exception))
} ?: emit(Lce.Content(inv))
}
}
fun getLocalInv() = flow.asLiveData()
fun updateInv() =
viewModelScope.launch {
repo.updateInv()
}
}
В этом классе я создаю поток, который устанавливает состояние загрузки, запрашивает удаленные данные из сети, когда он получает результат, он подписывается на базу данных комнат и преобразует поток, автоматически возвращаемый из БД, в поток, который знает состояние сетевой вызов, а также данные из базы данных.
Что в этом не так и что я не могу исправить, это следующие две проблемы:
1) Структурируя свой код таким образом, я должен дождаться ответа сети, прежде чем отправлять какие-либо данные. Я бы хотел вернуть поток из базы данных комнаты и показать старые данные, запустить обновление сети и обновить пользовательский интерфейс свежими данными. Но мне нужно было структурировать свой код таким образом, потому что это единственный способ, о котором я мог думать, который мог бы сообщить пользовательскому интерфейсу, не удалось ли сетевой вызов или нет.
2) Технически этот код может работать только при первом выполнении и в случае сбоя сетевого вызова. Если бы я хотел вручную запустить обновление, я бы не смог, потому что поток запускается только тогда, когда он впервые собирается (первое выполнение) или когда база данных комнаты испускает изменение (поэтому, если сеть не выходит из строя, и я сохраняю результат в дб).
Если вам это нужно, код репо такой:
val database = Database.getDb()
val remote = RemoteDataSource()
fun getInv(): Flow<List<Inv>> = database.invDao().getInv()
suspend fun updateInv(): Exception? {
return try {
val inv = remote.getInv()
database.invDao().saveInvs(inv)
null
} catch (e: Exception) {
e.printStackTrace()
e
}
}
Где remote.getInv()
- это просто модифицированная сопрограмма приостановки, а database.invDao () - это:
@Dao
interface InvDao {
@Query("SELECT * FROM Inv")
fun getInv(): Flow<List<Inv>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun saveInv(inv: Inv)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun saveInvs(invs: List<Inv>)
}
Мне не нужно иметь все данные в одном потоке, если это не рекомендуется, мне просто нужно знать, как правильно реализовать хороший репозиторий, используя комнату с потоком и модифицируя сопрограмму, и имея db как единственный источник истины.