Изменяемое значение Live Data обновляется при создании фрагмента

Я создал простой фрагмент входа в систему с моделью представления. Вот фрагмент:

class LoginFragment : Fragment() {

companion object {
    fun newInstance() = LoginFragment()
}

private lateinit var viewModel: LoginViewModel

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    return inflater.inflate(R.layout.login_fragment, container, false)
}

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    viewModel = ViewModelProviders.of(this).get(LoginViewModel::class.java)

    viewModel.loginState.observe(this, Observer{
        handleState(it)
    })

    login_button.setOnClickListener {
        viewModel.isUserValid(username.text.toString(), pass.toString())
    }
}

private fun handleState(status: RegisterState) {
    if (status.statusMessage.equals("Good"))
        view?.findNavController()?.navigate(R.id.action_registerFragment_to_homeFragment)
    else
        Snackbar.make(login_container, "Welcome to SwA", Snackbar.LENGTH_LONG).show();
}
}

и вот моя модель просмотра:

class LoginViewModel : ViewModel() {

lateinit var auth: FirebaseAuth

private var _loginState = MutableLiveData<LoginState>()
val loginState : MutableLiveData<LoginState> get() = _loginState

init {
    loginState.value = LoginState()
}

fun isUserValid(email: String, password: String): Boolean {
    //Add call to authenticate through firebase
    auth.signInWithEmailAndPassword(email, password)
        .addOnCompleteListener {
            if (it.isSuccessful) {
                // Sign in success, update UI with the signed-in user's information
                val user = auth.currentUser
                //updateUI(user)
            } else {
                // If sign in fails, display a message to the user.
                _loginState.value?.statusMessage = "Authentication Failed"
            }
        }

    return true
}
}

Это работает и регистрирует изменение состояния строки при неудачной попытке входа в систему, однако он также отправляет onChange() при загрузке фрагмента, вызывая появление панели закусок в пользовательском интерфейсе до того, как они фактически что-либо ввели при создании фрагмента. Как я могу инициализировать состояние просмотра, не вызывая onChange()?


person Doug Ray    schedule 31.08.2019    source источник


Ответы (1)


Класс LiveData имеет метод

 boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

который проверяет, находится ли владелец LifeCycle, Activity или Fragment в состоянии после STARTED, что означает для действия, если оно вызвало onStart().

Поэтому всякий раз, когда Activity или Fragment наблюдает за LiveData, он получает значение LiveData на setValue или PostValue после вызова onStart.

Один из способов предотвратить повторное обновление пользовательского интерфейса одним и тем же значением — использовать класс SingleLiveEvent, например здесь. Другой использует Event, например здесь.

person Thracian    schedule 31.08.2019
comment
Эй, фракиец, спасибо за ваш комментарий. Я заглянул в источник данных в реальном времени и нашел этот метод! Я переместил инициализацию модели представления и наблюдение за состоянием представления при создании фрагмента, но по-прежнему вижу, что закусочная появляется при переходе на экран входа в систему. Любая идея, почему это произойдет? - person Doug Ray; 31.08.2019
comment
Дело не в том, где вы инициализируете подписку, я имею в виду, где вы наблюдаете LiveData, она срабатывает в тот момент, когда фрагмент вызывает метод onStart. Вы должны использовать SingleLiveEvent для однократного действия, пока вы снова не вызовете setValue или postValue или не используете класс Event. Второй пример для To-Do — отличный пример для изучения LiveData и MVVM с чистой архитектурой. Мы используем его для наших приложений. - person Thracian; 31.08.2019
comment
Мы используем SingleLiveEvent для таких действий, как проверка входа в систему, переход к следующему фрагменту и т. д. Вы можете проверить это здесь. - person Thracian; 31.08.2019
comment
Я вижу спасибо за объяснение этого, я изначально пытался использовать SingleLiveEvent, но не могу найти правильную зависимость gradle и могу разрешить зависимость только для живых данных и изменяемых живых данных. Почему это не включено в пакет androidx.lifecycle? - person Doug Ray; 31.08.2019
comment
Я не знаю. Я думаю, что это должно было быть с 3 вариантами. 1- По умолчанию: значение может наблюдаться в любое время, когда наблюдатель ЗАПУЩЕН. 2- Одно событие: поведение SingleLiveEvent. 3- Конкретный наблюдатель наблюдает только один раз: это должно позволить одному наблюдателю наблюдать за значением только один раз, но позволить всем остальным также наблюдать за ним, в отличие от SingleLiveEvent. Также было бы здорово иметь какой-то метод, чтобы сообщать данные LiveData, которые они потребляют, чтобы не запускать другие наблюдатели. Если бы этот ответ сработал для вас, не могли бы вы его принять? - person Thracian; 01.09.2019