Как снова позвонить в блок сопрограмм LiveData - PullRequest
3 голосов
/ 05 октября 2019

Я использую версию LiveData "androidx.lifecycle: lifecycle-aliveata-ktx: 2.2.0-alpha05". Как только мой блок LiveData выполняется успешно, я хочу явно запустить его снова, например,

  1. Я перехожу к фрагменту
  2. Загрузка данных пользователя
  3. Я нажимаю "Удалить"находясь в том же фрагменте
  4. Данные пользователя должны обновляться

У меня есть фрагмент, где я наблюдаю мои LiveData, ViewModel с LiveData и репозиторием:

ViewModel:

  fun getUserLiveData() = liveData(Dispatchers.IO) {

   val userData = usersRepo.getUser(userId)

   emit(userData) 
}

Фрагмент:

viewModel.getUserLiveData(viewLifecycleOwner,
            androidx.lifecycle.Observer {.. 

Затем я пытаюсь добиться желаемого поведения, такого как:

viewModel.deleteUser()

viewModel.getUserLiveData()

Согласно документации, приведенной ниже, блок LiveData не будет выполняться, если он завершился успешно, и если я поместил while (true) внутри блока LiveData, то мои данные обновятся,однако я не хочу этого делать, так как мне нужно обновить свое представление реактивно.

Если [блок] завершается успешно, или отменяется по причинам, отличным от [LiveData] становится неактивным, он не будет быть повторно выполненным даже после того, как [LiveData] пройдет активный неактивный цикл.

Возможно, мне чего-то не хватает, как я могу использовать тот же LiveDataScope для достижения этой цели? Любая помощь будет оценена.

Ответы [ 3 ]

0 голосов
/ 02 ноября 2019

Чтобы сделать это с блоком liveData {..}, вам нужно определить некоторый источник команд и затем подписаться на них в блоке. Пример:

MyViewModel() : ViewModel() {
   val commandsChannel = Channel<Command>()

   val liveData = livedata {
      commandsChannel.consumeEach { command -> 
            // you could have different kind of commands 
             //or emit just Unit to notify, that refresh is needed
           val newData = getSomeNewData()
           emit(newData)
       }
   }

  fun deleteUser() {
   .... // delete user
   commandsChannel.send(RefreshUsersListCommand)
  }
}

Вопрос, который вы должны задать себе: может быть, вместо этого было бы проще использовать обычную MutableLiveData и изменять ее значение самостоятельно? когда вы можете собирать некоторый поток данных (например, Flow / Flowable из Room DB) и не очень хорошо для простых, не потоковых источников, к которым вам нужно обращаться за данными самостоятельно.

0 голосов
/ 04 ноября 2019

Для этого вы можете использовать MediatorLiveData .

Ниже приведен краткий обзор того, как вы можете достичь этого.

class YourViewModel : ViewModel() {

    val mediatorLiveData = MediatorLiveData<String>()

    private val liveData = liveData<String> {  }

    init {
        mediatorLiveData.addSource(liveData){mediatorLiveData.value = it}
    }

    fun refresh() {
        mediatorLiveData.removeSource(liveData)
        mediatorLiveData.addSource(liveData) {mediatorLiveData.value = it}
    }
}

Получите mediatorLiveData для ваших View и observe() то же самое, позвоните refresh()когда ваш пользователь удален, а остальные должны работать как есть.

0 голосов
/ 05 октября 2019

Вы можете создать наблюдаемую и установить значение в viewModel, а затем наблюдать его во фрагменте. Вот пример, который вы можете использовать:

ViewModel

  private val _myObservable = LiveData<*>
  val observable : LiveData<*> = _myObservable
  
  
  fun getUserLiveData(){

   val userData = usersRepo.getUser(userId)

  _myObservable.value = userData
}

Затем в Фрагмент :

viewModel.myObservable.observeNullsafe(owner){
//do anything you want to do with the user value
}

Так что теперь, когда вы звоните getUserData, он передает изменения в myObservable, и вы можете использовать их. вам не нужно излучать его самостоятельно.

Надеюсь, это поможет.

...