首页 > 解决方案 > 使用协程冻结 UI 的 Firebase 身份验证

问题描述

我正在尝试使用 Firebase 身份验证、协程和 MVVM 模式为我的应用程序做登录功能。关键是身份验证只有在成功时才会给我回调,否则它会冻结整个应用程序,我不知道为什么。我对android编程很陌生,我依赖互联网上的项目,我的代码可能很乱。这是我的代码:

Firebase 存储库:

class UserRepositoryImpl : UserRepository {

    private val authentication: FirebaseAuth by lazy {
        FirebaseAuth.getInstance()
    }

    override suspend fun firebaseLoginUser(email: String, password: String): Result<FirebaseUser?> {
        try{
            return when(val authResult =  authentication.signInWithEmailAndPassword(email, password).await())
            {
                is Result.Success<*> -> {
                    val firebaseUser = authentication.currentUser
                    Result.Success(firebaseUser)
                }
                is Result.Error -> {
                    Result.Error(authResult.exception)
                }
                is Result.Canceled ->{
                    Result.Canceled(authResult.exception)
                }
                else -> throw UnsupportedOperationException()
            }
        }
        catch (e: Exception){
            return Result.Error(e)

        }
    }

认证回调类:

sealed class Result<out R> {
    data class Success<out T>(val data: T) : Result<T>()
    data class Error(val exception: Exception) : Result<Nothing>()
    data class Canceled(val exception: Exception?) : Result<Nothing>()
}

自定义 Task.await() 方法:

suspend fun <T> Task<T>.await(): Result<T>
{
    if (isComplete)
    {
        val e = exception
        return if (e == null)
        {
            if (isCanceled){
                Result.Canceled(CancellationException("Task $this was cancelled"))}
            else {
                @Suppress("UNCHECKED_CAST")
                Result.Success(result as T)}
        }
        else {
            Result.Error(e) }
    }

    return suspendCancellableCoroutine { cont ->
        addOnCompleteListener {
            val e = exception
            if (e == null)
            {
                @Suppress("UNCHECKED_CAST")
                if (isCanceled) {
                    cont.cancel() }
                else {
                    cont.resume(Result.Success(result as T)) }
            }
            else {
                cont.resumeWithException(e) }
        }
    }
}

视图模型:

class AuthenticationViewModel(
        private val repository: UserRepositoryImpl
) : ViewModel() {

//Databinding values
var email: String? = null
     var password: String? = null

private val _toastMessage = MutableLiveData<Any?>()
     val toastMessage: LiveData<Any?>
          get() = _toastMessage

fun login() {
          if (email.isNullOrEmpty() || password.isNullOrEmpty()) {
               _toastMessage.value = R.string.login_noCredentials
               return
          }
          else{
               viewModelScope.launch {
                    when (val result = repository.firebaseLoginUser(email!!, password!!)) {
                         is Result.Success -> {
                                   // app.startHomeActivity()
                              }
                         }
                         is Result.Error -> {
                              _toastMessage.value = result.exception.message
                         }
                         is Result.Canceled -> {
                              _toastMessage.value = R.string.login_canceled
                         }
                    }
               }
          }
     }

标签: androidfirebase-authenticationkotlin-coroutines

解决方案


发现一个问题,这是因为我将 toastMessage 设置为 null 然后在登录片段中观察它,不知何故它冻结了我的 UI,将其删除修复了所有问题。


推荐阅读