Android MVVM - как заставить LiveData испускать данные, которые у него есть (принудительно запускать наблюдателя)

У меня есть ViewModel, который получает список из сети, и я заполняю RecyclerView данными (MyAvailabilityRepository возвращает MutableLiveData, поэтому я использую Transformations.switchMap):

class MyAvailabilityViewModel : ViewModel() {
    private val getListsParams = MutableLiveData<String>()
    private val getListsObservable = Transformations.switchMap(getListsParams) { 
        organizationId -> MyAvailabilityRepository.getSectionedLists(organizationId) 
    }

    fun getListsObservable() : LiveData<Resource<MutableList<SectionedAvailabilityList>>> {
        return getListsObservable
    }

    fun fetchLists(organizationId: String, forceRefresh: Boolean = false) {
        if (getListsParams.value == null || forceRefresh) {
            getListsParams.value = organizationId
        }
    }
}

onActivityCreated фрагмента:

override fun onActivityCreated(savedInstanceState: Bundle?) {
    ...
    viewModel.getListsObservable().observe(this, Observer { // populate RecyclerView })
    viewModel.fetchLists(organizationId)
}

Поскольку getListParams.value в первый раз равно нулю, он установит getListsParams.value = organizationId, запустит switchMap и вызовет репозиторий для получения списка из сети.

Когда я хочу принудительно выполнить обновление (путем pull-to-refresh) и снова вызвать сеть, я могу использовать forceRefresh = true:

override fun onRefresh() {
    viewModel.fetchLists(organizationId, forceRefresh = true)
}

Он установит значение organizationId и запустит преобразования, которые затем вызовут сеть.

Но у меня есть сценарий, в котором я очищаю данные из своего адаптера RecyclerView. Если после этого пользователь нажмет кнопку, я хотел бы снова запустить наблюдатель, чтобы повторно заполнить адаптер данными, которые getListsObservable уже получил. Я не хочу вызывать forceRefresh по этому поводу, потому что я уверен, что у меня уже есть данные, и я просто хотел бы снова запустить наблюдателя, чтобы мой пользовательский интерфейс обновился существующими данными. Поскольку getListParams.value в этот момент не является нулем, то когда я вызываю fetchLists(organizationId) позже, ничего не происходит.

Есть идеи, как я могу добиться этого с моей текущей настройкой?


person Mathbl    schedule 28.06.2018    source источник


Ответы (3)


Да, ответ Хун Дуаня идеален. Я просто собираюсь расширить этот ответ здесь,

Лучше всего использовать функцию расширения.

Моя функция расширения выглядит так,

fun <T> MutableLiveData<T>.forceRefresh() {
    this.value = this.value
}

Функция вызывающего абонента выглядит так,

mutableLiveDataObject.forceRefresh()

Удачного кодирования !!

person Narshim    schedule 05.04.2019

Попробуйте removeObservers() и observe() еще раз:

viewModel.getListsObservable().removeObservers(this)
viewModel.getListsObservable().observe(this, Observer { // populate RecyclerView })

потому что:

Если у LiveData уже есть набор данных, он будет доставлен наблюдателю.

См. документы.

Или, может быть, вы можете изменить getListsObservable(), чтобы вернуть MutableLiveData, а затем вызвать setValue вручную:

fun loadCurrentData() {
    getListsObservable.value = getListsObservable.value
}
person Hong Duan    schedule 28.06.2018

Я принудительно обновляю этот подход -

if (mainViewModel.mutable != null && mainViewModel.mutable.getValue()) {
    mainViewModel.mutable.setValue(mainViewModel.mutable.getValue());
}
person Gk Mohammad Emon    schedule 03.08.2020