RunBlocking с Dispatcher связь не работает - PullRequest
1 голос
/ 25 октября 2019

Я переключил свой контекст на Dispatcher.Main , чтобы показать пользовательский интерфейс, но данные извлекаются при запуске блокировки, но не могут отображаться в RecylerView

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

что я делаю не так и как правильно вернуть данные от одного Диспетчера к другому.

Я пробовал другой способ

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 (операция ввода-вывода) и отобразить эти данные в RecyclerView (операция основного потока)

1 Ответ

2 голосов
/ 25 октября 2019

Это потому, что вы должны переключать контекст после получения данных:

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, вам следует избегать этого. Причины здесь .

Как запустить сопрограмму в Android Activity / Fragment?

Сначала я предлагаю использовать в ViewModel или Presenter, но если вы хотите запустить сопрограмму в Activity / Fragment, вам понадобится способ контролировать и управлять ее отменой, чтобы избежать утечки памяти,Решение для этого будет:

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
 }
}
...