LiveData onChanged вызывается несколько раз с одними и теми же данными при использовании FirebaseAuth - PullRequest
0 голосов
/ 07 мая 2020

У меня есть логин, который реализует аутентификацию Firebase с использованием электронной почты и пароля. Что он делает, так это отправляет введенные пользователем адрес электронной почты и пароль в функцию FirebaseAuth и получает ответ через LiveData, а затем отслеживает его.

Проблема в том, что при неудачном входе в систему или недействительных учетных данных он должен один раз выдать сообщение , но на самом деле произошло то, что он тост несколько раз, может быть, более 4 раз (из-за этого тост показывался очень долго).

LoginActivity

    private fun signInWithEmailAndPassword(email: String, password: String){
        val authResult = viewModel.authWithEmailPassword(email, password)
        handleAuthenticationResult(authResult)
    }

    private fun handleAuthenticationResult(authResult: LiveData<Resource<AuthResult>>){
        authResult.observe(this, object : Observer<Resource<AuthResult>>{
            override fun onChanged(it: Resource<AuthResult>?) {
                when(it){
                    is Resource.Loading -> {
                        toggleLoadingIndicator(true)
                    }
                    is Resource.Success -> {
                        toggleLoadingIndicator(false)

                        val isNewUser = it.data.additionalUserInfo?.isNewUser ?: true

                        if(isNewUser) gotoIntroActivity()
                        else gotoMainActivity()
                    }
                    is Resource.Failure -> {
                        toggleLoadingIndicator(false)

                        when(it.throwable){
                            is FirebaseAuthException -> Toast.makeText(this@LoginActivity, getString(R.string.error_credentials_invalid), Toast.LENGTH_SHORT).show()
                            else -> Toast.makeText(this@LoginActivity, getString(R.string.error_login_failed), Toast.LENGTH_SHORT).show()
                        }
                    }
                }
            }
        })
    }

ViewModel

    fun authWithEmailPassword(email: String, password: String): LiveData<Resource<AuthResult>>{
        return AuthRepository.signInWithEmailAndPassword(email, password)
    }

FirebaseAuth

    private var authResult: MutableLiveData<Resource<AuthResult>> = MutableLiveData()

    fun signInWithEmailAndPassword(email: String, password: String): LiveData<Resource<AuthResult>>{
        authResult.value = Resource.Loading()

        mAuth.signInWithEmailAndPassword(email, password)
                .addOnCompleteListener{
                    if(it.isSuccessful) authResult.value = Resource.Success(it.result!!)
                    else authResult.value = Resource.Failure(it.exception!!)
                }

        return authResult
    }

Resource

sealed class Resource<out T> {
    class Loading<out T> : Resource<T>()
    data class Success<out T>(val data: T) : Resource<T>()
    data class Failure<out T>(val throwable: Throwable) : Resource<T>()
}

Почему это случилось и как это исправить? Должен ли я удалять наблюдателя каждый раз, когда срабатывает Resource.Failure?

1 Ответ

1 голос
/ 07 мая 2020

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

Чтобы исправить это, сделайте следующее:

  1. В вашей модели просмотра объявить живые данные:

val authResult: MutableLiveData<Resource<AuthResult>> = MutableLiveData()

В onCreate () вашей деятельности подпишитесь на эти liveData:

viewModel.authResult.observe(this, ... [the rest of your code]

когда вы получите результат аутентификации, просто опубликуйте его в liveData. Не подписывайтесь повторно на живые данные, не создавайте новые живые данные.

authResult.postValue(resource)

...