Android ViewModel MutableLiveData обновляется несколько раз

Сценарий

Привет, у меня есть Activity с ViewPager. В ViewPagerAdapter я создаю экземпляры одного и того же фрагмента с разными данными. И в каждом случае я инициализирую ViewModel

val dataViewModelFactory = this.activity?.let { DataViewModelFactory(it) }
mainViewModel = ViewModelProviders.of(this, dataViewModelFactory).get(MainViewModel::class.java)

В моем фрагменте я наблюдаю два MutableLiveData при вызове API

mainViewModel.isResponseSuccessful.observe(this, Observer { it ->

        if(it) {
            //do Something
        }else{
            Toast.makeText(activity, "Error in Sending Request", Toast.LENGTH_SHORT).show()
        }


    })

    mainViewModel.isLoading.observe(this, Observer {
        if (it) {
            println("show progress")
        } else {
            println("dismiss progress")
        }
    })

В каждом фрагменте по нажатию кнопки я загружаю другой фрагмент. И при необходимости вызов и API для получения данных.

ПРОБЛЕМА

В моем фрагменте код попадает в блок наблюдения несколько раз. Когда я возвращаюсь от одного фрагмента к предыдущему, даже если API не вызывается, код в блоке наблюдения выполняется.

Что я пробовал

Я пробовал использовать экземпляр активности в инициализации ViewModel

mainViewModel = ViewModelProviders.of(activity,dataViewModelFactory).get(MainViewModel::class.java)

Но не вышло.

Пожалуйста помоги,


person The Bat    schedule 24.08.2020    source источник
comment
Когда вы вернетесь к своему фрагменту, ViewModelProvider возвращает существующую модель просмотра вместо создания новой, так что liveata может быть уже установлена, и любое значение, которое она содержит, испускается.   -  person Pawel    schedule 24.08.2020
comment
@Pawel Да, предположим, что во фрагменте A я сделал это значение истинным и выполнил всю обработку, которую сделал. И затем я перехожу к фрагменту B. Теперь, когда я возвращаюсь к фрагменту A, он снова выдает «истинное» значение? Как я могу предотвратить это, я не хочу выполнять всю обработку, которую я делал, делая это правдой в первый раз.   -  person The Bat    schedule 24.08.2020
comment
Либо добавьте метод, который очищает ваши живые данные, когда вы оставляете фрагмент, либо вообще не используйте модель просмотра.   -  person Pawel    schedule 24.08.2020
comment
спасибо, как мне очистить мои живые данные @Pawel   -  person The Bat    schedule 24.08.2020


Ответы (2)


Если вы хотите предотвратить многократные вызовы вашего наблюдателя, вы можете просто изменить MutableLiveData на SingleLiveEvent. Прочтите это

person Александр Рябов    schedule 24.08.2020
comment
В этом случае, если я нахожусь в своем фрагменте A, вызываю API и показываю диалог прогресса, он будет отображаться только один раз, а не для другого вызова API. Я хочу, чтобы мои живые данные наблюдались только тогда, когда мой фрагмент отображается на экране, и не сохраняют значение, когда я вернусь - person The Bat; 24.08.2020

Это может вам помочь:

import java.util.concurrent.atomic.AtomicBoolean

class OneTimeEvent<T>(
    private val value: T
) {

    private val isConsumed = AtomicBoolean(false)

    private fun getValue(): T? =
        if (isConsumed.compareAndSet(false, true)) value
        else null

    fun consume(block: (T) -> Unit): T? =
        getValue()?.also(block)
}

fun <T> T.toOneTimeEvent() =
    OneTimeEvent(this)

Во-первых, если вы хотите опубликовать значение в LiveData, используйте функцию расширения toOneTimeEvent(), чтобы обернуть его в OneTimeEvent:

liveData.postValue(yourObject.toOneTimeEvent())

Во-вторых, когда вы наблюдаете на LiveData, используйте функцию consume { } для доставленного значения, чтобы получить возможность OneTimeEvent. Вы будете уверены, что блок consume { } будет выполнен только один раз.

viewModel.liveData.observe(this, Observer {
            it.consume { yourObject ->
                // TODO: do whatever with 'yourObject'
            }
        })

В этом случае, когда фрагмент возобновляется, ваш блок кода больше не выполняется.

person aminography    schedule 24.08.2020