Как организовать подписку на 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 шт):

Автор решения: pie

Например вот так, как вариант.

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
}
→ Ссылка