Firebase Auth + Pixel Mobile Network + Suspend Coroutine = Bug?

Firebase Auth + Pixel Mobile Network + Suspend Coroutine = Bug?

一切正常,例如,三星 (Android 11)、华为 (Android 10),除了至少 Google Pixel 2 (Android 11),Google Pixel 5 (Android 11)。 这些设备上的 Wi-Fi 也没有问题。

有一个注册屏幕。用户输入数据并点击“注册”按钮。

一切正常,直到用户执行以下操作:

  1. Enable the mobile network -> Click on the "sign up" button -> For example, the message "email is already in use" -> Disable the mobile network -> Click on the "sign up" button -> The suspended coroutine never continues (FirebaseNetwork 异常是预期的)

但是,它有效:

  1. Enable the mobile network -> Disable the mobile network -> Click on the "sign up" button -> For example, the message "email is already in use" (一切正常因为挂起的协程已经唤醒)

底线:Firebase 不会抛出 FirebaseNetwork 或任何异常,因此用户界面“冻结”(我在处理请求时禁用了表单) 当用户在启用移动网络的情况下提交表单,然后在关闭移动网络的情况下提交表单。

private suspend fun handleResult(task: Task<AuthResult>) =
                suspendCoroutine<AuthResult> { continuation ->
                    task.addOnSuccessListener { continuation.resume(it) }
                        .addOnFailureListener { continuation.resumeWithException(it) }

                }

我用 答案解决了问题。 代码现在看起来像:

private suspend fun handleResult(task: Task<AuthResult>) =
            withTimeout(5000L) {
                suspendCancellableCoroutine<AuthResult> { continuation ->
                    task.addOnSuccessListener { continuation.resume(it) }
                        .addOnFailureListener { continuation.resumeWithException(it); }
                }
            }

我是否需要使用带超时的 suspendCancellableCoroutine 而不是始终与 Firebase 一起使用 suspendCoroutine 以避免在其他设备上出现这些错误?

我不知道这是否是原因,但这可能会有所帮助。已经有一个挂起函数可以处理 Google 任务,而无需您自己实现 suspendCancellableCoroutine。他们的实现比你的更彻底(大约 30 行代码)并且可能处理一些你没有的边缘情况。当您调用它时任务已经完成时,它还会优化结果,并且它会正确处理取消,而您的则不会。

函数为Task.await()。如果它对您不可用,请将此依赖项添加到您的 build.gradle:

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.0"

结合await()(谢谢@Tenfour04)+withTimeout()解决了这个问题。 Firebase 似乎没有网络身份验证调用超时。

build.gradle 暂停 await()(将“x.x.x”替换为最新版本):

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-play-services:x.x.x'

例如:

private val firebaseAuth: FirebaseAuth

suspend fun create(userInitial: UserInitial): AuthResult = withTimeout(5000L) {
            firebaseAuth.createUserWithEmailAndPassword(
                userInitial.email,
                userInitial.password
            )
                .await()
        }

withTimeout() 如果超过超时则抛出 TimeoutCancellationException