在协程更新变量并且协程完成后检索 ViewModel 变量,Android Kotlin 协程



我正在 Kotlin 中为 android 开发一个应用程序,并编写重置密码片段,其中逻辑如下:

用户输入电子邮件地址以重置密码。 输入电子邮件并按下"发送重置代码"后,ViewModel 函数 触发forgetPasswordViewModel.sendAuthCode(),通过存储库向房间数据库发送查询,以检查房间数据库中是否存在包括电子邮件地址在内的用户数据,如果该电子邮件地址存在由非空结果指示,系统将检索密码的重置代码(authCode)并通过电子邮件发送给用户。如果系统中不存在电子邮件地址(由空用户数据指示),则视图模型中validEmail的布尔变量设置为true。这有助于我在忘记密码片段中生成适当的吐司消息。

我在 ForgetPassword 片段中调用该方法forgetPasswordViewModel.sendAuthCode(),然后检查validEmail变量,该变量将指示系统中是否已存在电子邮件,但是该变量validEmail始终返回false,因为协程forgetPasswordViewModel.sendAuthCode()仍在后台线程中运行,并且直到那时validEmailyet不会更新布尔变量, 因此,在运行片段的主线程上,代码继续运行以下语句,该语句从 ViewModel 检索validEmail,此时该语句仍为 false,因为协程函数forgetPasswordViewModel.sendAuthCode()尚未将变量设置为 true。

Kotlin 中是否有任何函数可供我使用,以便我的代码将等到协程完成执行并更新变量,然后再继续执行代码。我在 StackOverFlow 上看到了一些解决方案,人们建议使用 join(),但我只有一个协程,布尔变量validEmail是 ViewModel 范围变量。谁能引导我朝着正确的方向前进。这是我的代码:

查看模型:

class ForgetPasswordViewModel(val repository: Repository) : ViewModel() {
//Variable to contain user email address
lateinit var emailAddress: String
var validEmail: Boolean = false

//Getting instance of Repository
val repo = Repository()
//Send Password reset code to email
fun sendAuthCode() {
viewModelScope.launch {
val userData = repo.getUserDataByEmail(emailAddress)
if (userData != null) {
val authCode = userData.authCode
//Send email to new user with account details
val sender = SendMail(
AppContext.appContext!!,
emailAddress,
"Password reset code",
"Dear ${userData.firstName},nn" +
" This is your reset code.nn +
"Password reset code: $authCode n"
)
sender.execute()
validEmail = true //here I set it to true to indicate that things went well
}
}
}
}

以下是ForgetPassword Fragment的片段:

// Set onClickListener to btnRequestPassword button
viewBinding.btnRequestPassword.setOnClickListener{
forgetPasswordViewModel.emailAddress = emailAddress.text.toString()
if(forgetPasswordViewModel.emailAddress.length < 3) { //The theoretical minimum length of any email address is 3
ValidationChecks.showToast("Enter valid email address",context)
} else{
forgetPasswordViewModel.sendAuthCode()
if(!forgetPasswordViewModel.validEmail){
Toast.makeText(context, "Email not found in the system",Toast.LENGTH_SHORT)
} else {
Toast.makeText(context, "Password reset code sent successfully!",Toast.LENGTH_SHORT)
}

如果有人能把我推向正确的方向,我将不胜感激。 亲切问候 萨利克

由于您期望同步行为,因此您可以在片段中启动协程并使sendAuthCode函数挂起。

片段:

...
viewLifecycleOwner.lifecycleScope.launch {
val validEmail = forgetPasswordViewModel.sendAuthCode()
if(!validEmail){
Toast.makeText(context, "Email not found in the system",Toast.LENGTH_SHORT)
} else {
Toast.makeText(context, "Password reset code sent successfully!",Toast.LENGTH_SHORT)
}
}
...

视图模型:

suspend fun sendAuthCode(): Boolean {
val userData = repo.getUserDataByEmail(emailAddress)
if (userData != null) {
val authCode = userData.authCode
//Send email to new user with account details
val sender = SendMail(
AppContext.appContext!!,
emailAddress,
"Password reset code",
"Dear ${userData.firstName},nn" +
" This is your reset code.nn +
"Password reset code: $authCode n"
)
sender.execute()
return true
}
return false
}

确保您的 DAO 方法处于挂起状态,以便它们从主线程中运行。或者,如果在操作过程中存在阻塞调用,viewLifecycleOwner.lifecycleScope.launch {...}在主线程上运行,则更改协程上下文。像这样的事情就可以了:

suspend fun sendAuthCode(): Boolean = withContext(Dispatchers.IO) {
...
}

最新更新