繁体   English   中英

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

[英]Retrieving ViewModel variable after a coroutine has updated the variable and the coroutine is completed, Android Kotlin Coroutines

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

用户输入 email 地址重置密码。 After the email is entered and 'Send reset code' is pressed, the ViewModel function forgetPasswordViewModel.sendAuthCode() is triggered which sends a query through repository to the Room database to check if the user data including email address exists in the room database, if如果不是 null 结果表明存在 email 地址,则系统检索密码的重置代码(authCode)并将其通过电子邮件发送给用户。 If the email address doesn't exist in the system (indicated by null userData), a boolean variable validEmail in the view model is set to true . 这有助于我在 ForgetPassword 片段中生成适当的 toast 消息。

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

Kotlin 中是否有任何 function 我可以使用它,以便我的代码将等到协程完成执行并在我的代码继续执行之前更新变量。 我在 StackOverFlow 上看到了一些解决方案,人们建议使用 join() 但我只有一个协程,并且 Boolean 变量validEmail是 ViewModel scope 变量。 任何人都可以指导我正确的方向。 这是我的代码:

查看 MODEL:

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},\n\n" +
                            " This is your reset code.\n\n +
                            "Password reset code: $authCode \n"
                )
                sender.execute()
                validEmail = true //here I set it to true to indicate that things went well
            }
        }
    }
}

这是 ForgetPassword 片段的片段:

 // 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 function 暂停。

分段:

...
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},\n\n" +
                    " This is your reset code.\n\n +
            "Password reset code: $authCode \n"
        )
        sender.execute()
        return true
    }

    return false
}

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM