【问题标题】:Wait for coroutine to finish to handle user click等待协程完成处理用户点击
【发布时间】:2019-06-19 15:01:50
【问题描述】:

我正在创建一个“会话”系统,用户可以在其中启动、完成和查看他的会话。
用户通过第一个片段创建他的会话,然后进入“会话中”片段。
如果他在完成会话之前返回主菜单,我希望他直接进入“会话中”而不通过“新会话”片段。

所有会话数据都存储在本地数据库中,我使用 Kotlin 协程从数据库中获取数据(参见下面的代码示例)

这是我第一次使用协程,我承认它有点模糊 对我来说,欢迎所有的帮助

问题是当用户按下按钮导航时,协程完成验证后查看是否有当前会话,导致验证一个null 对象或当前会话的上一个会话,因此导航到“新会话”片段

我需要的是一种等待协程完成然后 处理按钮点击

这里写的所有代码都包含在viewModel中
这就是我设置作业/范围的方式

private var viewModelJob = Job()
private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)

这就是我启动协程的方式:

private fun initializeLastSession() {
    uiScope.launch {
    lastSession.value = getLastSessionFromDatabase()
    }
}

private suspend fun getLastSessionFromDatabase(): Session? {
    return withContext(Dispatchers.IO) {
        var session = database.getLastSession()
        session
    }
}

在这个函数内部进行验证

fun isSessionActive(): Boolean {
//Simplified
    if (lastSession.value = null) {
        return false
    } else if (...) {
        return true
    } else {
        return false
    }

当用户按下导航按钮时,从片段 itlsef 中的 if 语句调用最后一个函数“isSessionActive”。
如果为真,则导航到“InSession”,否则导航到“newSession”

我见过多种等待协程完成的方式,但没有一种方式与我启动它的方式相匹配,更没有适合我的解决方案。

【问题讨论】:

    标签: android kotlin-coroutines


    【解决方案1】:

    您能否允许我举一个与您的代码无关的简单示例?但与问题密切相关:

    uiScope.launch{
     withContext(Dispatchers.IO){
      val dataFromDatabase = getSomeDataFromDatabase()
      if (dataFromDatabase.notEmpty()){ //or something
        withContext(Dispatchers.Main){
         //send data to fragment here :)
        }
       }
     }
    }
    

    编辑:

    既然你说你在ViewModel,你不需要返回任何值,你需要观察改变的值:

    //on top of your ViewModel class: 
    
    val yourVariableName: MutableLiveData<Boolean> = MutableLiveData()
    
    //than in your method: 
        uiScope.launch{
         withContext(Dispatchers.IO){
          val dataFromDatabase = getSomeDataFromDatabase()
          if (dataFromDatabase.notEmpty()){ //or something
            withContext(Dispatchers.Main){
             if (lastSession.value = null) {
            yourVariableName.value = false
        } else if (...) {
            yourVariableName.value = true
        } else {
            yourVariableName.value = false
        }
            }
           }
         }
        }
    

    比在你的片段中:

    //after you have successfully instantiated the `ViewModel`: 
    mViewModel.yourVariableName.observe(this , Observer{ valueYouAreObserving->
     // and here you have the value true ore false 
     Log.d("Tag", $valueYouAreObserving)
    })
    

    【讨论】:

    • 感谢您的回复,我想我已经理解了代码,但我不确定如何处理它。问题是我没有做任何 ui 更改,我只需向我的片段返回一个布尔值以确定我是否需要转到一个片段或另一个
    • 只需要更新评论以免混淆
    • 好的,最后一个问题,你说将数据发送到片段,实际上在片段中我调用了这个应该返回布尔值的函数。在这个函数中,我有一个 when 语句来决定我是 return 假还是真。如何从 withContext 和 uiScope.launch 中“传输”这个返回布尔值?我尝试了 return@withContext 但 IDE 不喜欢其中有 2 个的事实 我还尝试在“uiScope.launch”前面放一个 return 但它返回一个 Job 对错误或信息缺失感到抱歉,整整 2 天都在这上面,变得非常倾斜
    • 我已经编辑了帖子以解释我在上一条评论中所说的内容
    • 嗯,谢谢你提供的帮助,还是比我开始的好,我会继续解决这个问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-14
    • 1970-01-01
    相关资源
    最近更新 更多