我目前正在学习如何将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>() {
private Task<Void> signOutIdps(@NonNull Context context) {
...
return GoogleSignIn.getClient(context, GoogleSignInOptions.DEFAULT_SIGN_IN).signOut();
}
并确定也许永远不会启动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不可用是有道理的,因为用户界面根据身份验证状态而发生了很大变化。