使用分派器通讯的RunBlocking无法正常工作

时间:2019-10-25 07:04:30

标签: android kotlin dispatcher kotlin-coroutines

  

我已将上下文切换为 Dispatcher.Main 以显示UI,但在runBlocking上获取了数据,但无法在 RecylerView

中显示
runBlocking {
            var fruits = fetchFruitList()
            withContext(Dispatchers.Main){
                recyclerView.adapter = FruitAdapter(fruits);
            }
        }

我在做什么错,将数据从一个Dispatcher返回到另一个Dispatcher的适当方法是什么?

我尝试了另一种方法

GlobalScope.launch {
            withContext(Dispatchers.IO){
                var fruits = arrayOf("Grapes","Apple","Mango","TuttiFruit","PineApple",
                        "Pomegrante","Apple","Mango","TuttiFruit","PineApple",
                        "Pomegrante","Apple","Mango","TuttiFruit","PineApple").toList()
                return@withContext
            }
            recyclerView.adapter = FruitAdapter(fruits)
        }

,但以上面的方式I have to declare fruits as global,而我不想让它全局运行。有没有一种方法可以将数据从一个“调度程序”队列返回到另一个

  

我必须从Api(IO操作)中获取数据并在RecyclerView(主线程操作)中显示该数据

1 个答案:

答案 0 :(得分:2)

那是因为在获取数据之后必须切换上下文:

GlobalScope.launch(Dispatchers.IO){
       var fruits = arrayOf("Grapes","Apple","Mango","TuttiFruit","PineApple",
                    "Pomegrante","Apple","Mango","TuttiFruit","PineApple",
                    "Pomegrante","Apple","Mango","TuttiFruit","PineApple").toList()

       withContext(Dispatchers.MAIN){
           recyclerView.adapter = FruitAdapter(fruits)
       }        
}

根据评论进行编辑:

对于runBlocking,请查阅文档第一段。

  

运行一个新的协程并中断当前线程,直到   它的完成。协程不应该使用此功能。它   旨在将常规阻止代码桥接到   以悬挂样式编写,用于主要功能和   测试。

其次,您要求使用GlobalScope。是的,如果您使用Android进行协同程序,则应避免这种情况。 Reasons here

如何在Android活动/片段中启动协同程序?

首先,我建议在ViewModelPresenter中使用,但是如果要在活动/片段中启动协程,则需要一种方法来控制和管理它的取消以避免内存泄漏。 解决方案是:

private val job: Job = Job()
                                              //or Dispatchers.IO
private val fragmentScope = CoroutineScope(Dispatchers.MAIN + job)

//launch a coroutine later in Activity/Fragment

fragmentScope.launch{
  //the default coroutine dispatcher would be the defined dispatcher above
}

override fun onDestroy(){
  super.onDestroy()
  fragmentScope.cancel()
}

关于您的问题:

  

我在做什么错,返回数据的适当方法是什么   从一个调度员到另一个调度员

如果要从其他上下文返回值,也可以尝试以下解决方案:

someScope.launch(Dispatchers.MAIN){
 var data = withContext(Dispatchers.IO){
  val someData = fetchSomeData()
  return@withContext data
}
if(data.isAvailable()){ //for example
 //runing on the main thread
 }
}