【问题标题】:how to use values from coroutines outside of coroutines如何在协程之外使用协程中的值
【发布时间】:2020-10-29 12:49:43
【问题描述】:

如何在调用它的协程之外使用来自房间数据库的响应

我需要使用协程来执行来自房间数据库的请求,然后将此数据显示在 recyclerview 中。我遇到的问题是我无法从数据库中获得响应以显示在协程之外。

我的代码。

class seconddisplay : AppCompatActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.second_display)

    GlobalScope.launch {
        val respo = second_Database.getInstance(context = this@seconddisplay).DAO().seeAllcodes()

    }

    second_recyclerview.apply {
        layoutManager = LinearLayoutManager(this@seconddisplay)
        adapter = displayAdapter(respo)
    }
}

我也不能将 recyclerview 代码放在协程中,因为它说你不能触及视图的层次结构。

【问题讨论】:

  • 不,您不能,您应该将该代码放在启动块中。在 respo call bas 完成之前,您无法暂停代码(阻止它除外)。它是异步的。

标签: android kotlin android-room kotlin-coroutines coroutine


【解决方案1】:

你可以使用respo变量作为类的全局变量。然后使用属性withContext(Dispatcher.main)来使用主线程并等待结果。像这样:

private var respo: YourDataType? = null


override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   setContentView(R.layout.second_display)
   getRespo()
   
}

private fun getRespo(){
   val supervisorJob = SupervisorJob()
   val coroutineScope = CoroutineScope(Dispatchers.IO + supervisorJob)
   coroutineScope.launch {
      withContext(Dispatchers.Main) {
      respo = second_Database.getInstance(this@seconddisplay).DAO().seeAllcodes()
      second_recyclerview.apply {
      layoutManager = LinearLayoutManager(this@seconddisplay)
        if(respo!=null){
          adapter = displayAdapter(respo)
        }else{//handle respo being null, maybe show a message 
          }
        }
     
      }
   }
   
}

【讨论】:

  • 那么如果异步代码没有完成那么是 null 并且什么都没有发生?
  • 事情是异步代码正在主线程中执行,所以它被阻塞直到它完成。但是用 else 块来处理它是个好主意。刚刚编辑了答案
  • 为此,apply 应该放在 with 上下文中
  • 你是对的!我没有注意到我把它放在外面!我现在编辑所以它在里面!非常感谢!
【解决方案2】:

ActivityFragment 中,您可以使用lifecycleScope 启动协程,默认情况下它在Main 协程上下文中运行,因此您可以从那里更新您的UI:

lifecycleScope.launch {
    // call like this if `seeAllcodes()` method is suspend
    val respo = second_Database.getInstance(context = this@seconddisplay).DAO().seeAllcodes() 

    // call like this if `seeAllcodes()` method isn't suspend
    val respo = withContext(Dispatchers.IO) { // runs on background thread
        second_Database.getInstance(context = this@seconddisplay).DAO().seeAllcodes()
    }

    // update UI
    second_recyclerview.apply {
        layoutManager = LinearLayoutManager(this@seconddisplay)
        if (respo != null) {
            adapter = displayAdapter(respo)
        }
    }
}

要使用lifecycleScope,请将下一行添加到应用的 build.gradle 文件的依赖项:

implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.3.0-alpha05"

【讨论】:

  • 非常感谢。这有很大帮助。谢谢!
猜你喜欢
  • 1970-01-01
  • 2022-01-23
  • 2014-12-30
  • 2023-03-19
  • 2020-03-19
  • 1970-01-01
  • 2020-02-26
  • 1970-01-01
  • 2020-06-07
相关资源
最近更新 更多