使用runBlocking协程检索Firebase的AuthUI.signOut()结果时出现死锁

时间:2018-11-02 07:10:42

标签: android firebase kotlin firebase-authentication kotlinx.coroutines

我目前正在学习如何将Kotlin协程用于Android应用程序。让我着迷的一件事是同步处理异步过程的可能性。

因此,我的玩具应用程序基于MVVM架构模式,并使用Firebase实现了登录/注销功能。还有一个SignOut用例:

class FirebaseSignOut @Inject constructor(private val firebaseAuthUi: AuthUI) : SignOut {
    private lateinit var signOutResult: SignOutResult

    override fun execute(context: Context): SignOutResult {
        runBlocking {
            signOutResult = getSignOutResult(context)
        }

        return signOutResult
    }

    private suspend fun getSignOutResult(context: Context): SignOutResult {
        return suspendCoroutine { continuation ->
            firebaseAuthUi.signOut(context)
                    .addOnSuccessListener {
                        continuation.resume(SignOutSuccess)
                    }
                    .addOnFailureListener {
                        continuation.resume(SignOutError)
                    }
                    .addOnCanceledListener {
                        continuation.resume(SignOutCancel)
                    }
        }
    }

}

问题

从runBlocking开始的阻止永远不会解锁。

我通过用模拟代替getSignOutResult()来发现协程逻辑本身不是问题,例如:

private suspend fun getSignOutResult(context: Context): SignOutResult {
    delay(500)
    return SignOutError
}

然后,我能够跟踪到Firebase AuthUI的这一部分为止的阻止情况:

return Tasks.whenAll(
        signOutIdps(context),
        maybeDisableAutoSignIn
).continueWith(new Continuation<Void, Void>() {

https://github.com/firebase/FirebaseUI-Android/blob/master/auth/src/main/java/com/firebase/ui/auth/AuthUI.java#L325

private Task<Void> signOutIdps(@NonNull Context context) {
    ...
    return GoogleSignIn.getClient(context, GoogleSignInOptions.DEFAULT_SIGN_IN).signOut();
}

https://github.com/firebase/FirebaseUI-Android/blob/master/auth/src/main/java/com/firebase/ui/auth/AuthUI.java#L403

并确定也许永远不会启动DisableAutoSignIn Task。因此,死锁发生在GoogleSignIn的signOut()内部某处,无法跟踪。

问题

有人知道为什么会发生这种僵局吗?任何解决该问题的建议都将受到欢迎。

配置详细信息

我使用的是Kotlin和Firebase库的最新版本

firebaseCoreVersion = '16.0.4'
firebaseUiVersion = '4.1.0'
kotlinVersion = '1.3.0'
kotlinCoroutinesVersion = '1.0.0'

AuthUI决定只使用Google登录。


!请注意,我知道我可以使signOutResult变量可观察。但是在这种情况下,execute将无法返回结果。我真的很想这样做,因为这样的实现对于测试来说很容易模拟。在我的情况下,runBlocking会阻塞主线程进行注销这一事实在我的情况下是可以接受的-在此过程中UI不可用是有道理的,因为用户界面根据身份验证状态而发生了很大变化。

0 个答案:

没有答案