Как организовать подписку на LiveData + LoadingState
Нужно при изменении данных в БД оповещать RecyclerView. Всё хорошо работает если это напрямую подписка на LiveData. Если добавить в запрос некоторые действия для отображения индикатора загрузки, то всегда возвращается null или ошибка типов. Как можно сделать динамическое обновление из БД и индикацию?
// Dao
@Query("SELECT * FROM share")
fun getAll(): LiveData<List<Share>>
// Repository
val fetch = shareDao.getAll()
// ViewModel
val loadingStateLiveData = MutableLiveData<LoadingState>()
private fun fetch(): LiveData<List<Share>> {
val liveData = MutableLiveData<List<Share>>()
loadingStateLiveData.value = LoadingState.LOADING
viewModelScope.launch(Dispatchers.IO) {
try {
liveData.postValue(repository.fetch)
loadingStateLiveData .postValue(LoadingState.LOADED)
} catch (e: Exception) {
}
}
return liveData
}
// Fragment
viewModel.fetch().observe(viewLifecycleOwner, Observer {
if (it != null) {
binding.recyclerView.adapter = homeAdapter
homeAdapter.updateData(it)
}
})
Строка liveData.postValue(repository.fetch) возвращает:
Type mismatch.
Required: List<Share>!
Found: LiveData<List<Share>>
Если воспользоваться value -> liveData.postValue(repository.fetch.value) ошибка пропадает, однако, всегда приходит null.
Сделал такой вариант, выполняет то что нужно, однако, не уверен, что технически правильно.
val result: LiveData<List<Share>> = liveData<List<Share>> {
loadingStateLiveData.value = LoadingState.LOADING
try {
val liveData = repository.fetch
emitSource(liveData)
loadingStateLiveData.postValue(LoadingState.LOADED)
} catch (e: Exception) {
loadingStateLiveData.postValue(LoadingState.ERROR)
}
}
Ответы (1 шт):
Например вот так, как вариант.
sealed class Response<out R> {
data class Success<out T>(val data: T) : Response<T>()
data class Error(val exception: Exception) : Response<Nothing>()
object Loading : Response<Nothing>()
}
// ViewModel
val data: LiveData<Response<List<Share>>> = loadData()
private fun loadData(): LiveData<Response<List<Share>>> =
liveData(viewModelScope.coroutineContext + Dispatchers.IO) {
emit(Response.Loading)
try {
emit(repository.fetch)
} catch (exception: Exception) {
emit(Response.Error(exception))
}
}
// View (Fragment)
viewModel.data.observe(viewLifecycleOwner, { response ->
when (response) {
is Response.Loading -> { }
is Response.Success -> { }
is Response.Error -> { }
}
})
Ошибка возникает потому, что fetch у Вас LiveData<List<Share>>. Попробуйте в своем примере сделать так:
private fun fetch(): LiveData<List<Share>> {
val liveData: LiveData<List<String>>
loadingStateLiveData.value = LoadingState.LOADING
viewModelScope.launch(Dispatchers.IO) {
try {
liveData = repository.fetch
loadingStateLiveData .postValue(LoadingState.LOADED)
} catch (e: Exception) {
}
}
return liveData
}