这是完整的流程:
在用户配置文件中:
.clickable {
loginViewModel.onLogout()
isLogin= false
}
isLogin只有在doLogout完成后才应该赋值为false如何才能在此函数完成后才运行其他函数或代码?我能知道函数何时完成吗?
下面是ViewModel():
fun onLogout() {
viewModelScope.launch(Dispatchers.IO) {
withContext(Dispatchers.Main){
loginStatus = "out"
getUserType = null
}
FirebaseMessaging.getInstance().token.addOnCompleteListener {
val token = it.result
viewModelScope.launch(Dispatchers.IO) {
try {
repo.doLogout(token)
}catch (exp: Exception){
println("FCM token error")
}
}
}
}
}
这是来自repository:
suspend fun doLogout(token: String) {
val userId = appService.currentUser!!.id
realm.write {
var user = query<UserInfo>("_id = $0", userId).first().find()
if (user != null) {
user = findLatest(user)!!.also {
it.FCMToken.remove(token)
}
copyToRealm(user)
}
}
withContext(Dispatchers.Default) {
realm.syncSession.uploadAllLocalChanges()
appService.currentUser?.logOut()
}
}
6条答案
按热度按时间abithluo1#
你可以在你的logout()函数中接收一个回调lambda,并在你的异步工作完成时调用它。尽管我有点不喜欢这个解决方案。最好的解决方案是在你的ViewModel中公开一个logoutEffect SharedFlow,你的Composable收集它来接收logout事件。
bkkx9g8r2#
将
isLogin
变量移到视图模型中。g52tjvyc3#
把你所有的后台任务放到一个分配给变量的aysnc块中。在完成任务后,返回任意值。你可以在runBlocking {}块中等待这个值来暂停执行,直到注销完成。
57hvy0tb4#
我不建议这种解决方案用于您的情况,但对于您的问题“我可以知道函数何时完成吗?”,您可以使用invokeOnCompletion
但是,使用function作为参数或瓦尔isLogin = mutableStateOf(true)作为@DominicFischer回复
xuo3flqw5#
你的问题是,在
viewModel.onLogout()
中,你异步地启动了一个新的协程,而不是仅仅使它成为一个suspend函数。suspend函数是同步的。启动协程对调用者来说是异步的。你希望这个函数是同步的,因为你想等待它完成。您还需要摆脱
addOnCompleteListener
,因为这也是一个异步调用。(你在另一个异步调用中有一个异步调用,在第三个嵌套异步调用中,因为您在侦听器中启动了另一个协程!)这可以用await()
suspend函数调用来代替(因为suspend函数是同步的)。如果您得到一个未解析的引用并且无法导入await()
扩展函数,请确保在依赖项中使用的是-ktx
版本的Firebase库。当调用suspend函数时,不需要
withContext
,可以从repo.doLogout
调用中删除它。因此,将ViewModel函数更改为:
我不确定上面的
= withContext(Dispatchers.Main)
是否是必要的。我对Compose还不够熟悉,不知道从任何线程修改MutableState是否安全,所以我只是防御性地把它放在那里。我不熟悉Realm,所以我不能评论你的repo功能是否正确。
qaxu7uf26#
我找到了解决方案,没有错误的工作。
这是我在LoginlView中的onLogout:
我使用onCompletion来检查注销是否完成
由于这个函数被挂起,我调用**(from clickable())**一个协程如下: