使用 FirebaseAuth 时使用相同数据多次调用 LiveData onChanged
LiveData onChanged called multiple times with the same data when using FirebaseAuth
我有一个登录名 activity,它使用电子邮件和密码实施 Firebase 身份验证。它所做的是将用户输入的电子邮件和密码发送到 FirebaseAuth 函数并通过 LiveData 检索响应,然后观察它。
问题是,当登录失败或凭据无效时,应该吐司一次消息,但实际情况是多次吐司,可能超过4次(导致吐司显示很长时间).
登录活动
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
}
资源
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
触发时移除观察者吗?
LiveData 是您只创建和订阅一次的东西。在您的情况下,您每次获得身份验证结果时都会订阅它,因此会出现多个重复事件。
要解决此问题,请执行以下操作:
- 在您的视图模型中,声明实时数据:
val authResult: MutableLiveData<Resource<AuthResult>> = MutableLiveData()
- 在您的 Activity 的 onCreate() 中,订阅此 liveData:
viewModel.authResult.observe(this, ... [the rest of your code]
- 当您获得验证结果时,只需 post 将其发送到 liveData。不重新订阅直播数据,不新建直播数据。
authResult.postValue(resource)
我有一个登录名 activity,它使用电子邮件和密码实施 Firebase 身份验证。它所做的是将用户输入的电子邮件和密码发送到 FirebaseAuth 函数并通过 LiveData 检索响应,然后观察它。
问题是,当登录失败或凭据无效时,应该吐司一次消息,但实际情况是多次吐司,可能超过4次(导致吐司显示很长时间).
登录活动
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
}
资源
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
触发时移除观察者吗?
LiveData 是您只创建和订阅一次的东西。在您的情况下,您每次获得身份验证结果时都会订阅它,因此会出现多个重复事件。
要解决此问题,请执行以下操作:
- 在您的视图模型中,声明实时数据:
val authResult: MutableLiveData<Resource<AuthResult>> = MutableLiveData()
- 在您的 Activity 的 onCreate() 中,订阅此 liveData:
viewModel.authResult.observe(this, ... [the rest of your code]
- 当您获得验证结果时,只需 post 将其发送到 liveData。不重新订阅直播数据,不新建直播数据。
authResult.postValue(resource)