Как я могу использовать runblocking при нажатии кнопки

Какова цель runblocking ?. Могу ли я использовать его в OnClickListener ?. Здесь я использую runblocking {} в OnClickListener
Это мой код

mBinding.ivAdd.setOnClickListener{ println("before" + Thread.currentThread().id) runBlocking { println("in async" + Thread.currentThread().id) val job = launch { // launch new coroutine and keep a reference to its Job delay(1000L) println("World!" + Thread.currentThread().id) mBinding.tvNoDataFound.text = "test" } println("Hello,") println("after hello" + Thread.currentThread().id) delay(5000) job.join() // wait until child coroutine completes } println("after runBlocking" + Thread.currentThread().id) } 

Он показывает ошибку, подобную этой

  12-20 14:46:31.387 26915-26915/ I/System.out: before1 12-20 14:46:31.399 26915-26915/ I/System.out: in async1 12-20 14:46:31.405 26915-26915/ I/System.out: Hello, 12-20 14:46:31.405 26915-26915/ I/System.out: after hello1 12-20 14:46:32.410 26915-26937/I/System.out: World!1561 12-20 14:46:32.422 26915-26937/ E/AndroidRuntime: FATAL EXCEPTION: ForkJoinPool.commonPool-worker-2 android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6556) at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:907) at android.view.View.requestLayout(View.java:18728) at android.view.View.requestLayout(View.java:18728) at android.view.View.requestLayout(View.java:18728) at android.view.View.requestLayout(View.java:18728) at android.view.View.requestLayout(View.java:18728) at android.view.View.requestLayout(View.java:18728) at android.view.View.requestLayout(View.java:18728) at android.view.View.requestLayout(View.java:18728) at android.widget.TextView.checkForRelayout(TextView.java:7169) at android.widget.TextView.setText(TextView.java:4347) at android.widget.TextView.setText(TextView.java:4204) at android.widget.TextView.setText(TextView.java:4179) at MainActivity$onCreate$1$1$job$1.doResume(MainActivity.kt:164) at kotlin.coroutines.experimental.jvm.internal.CoroutineImpl.resume(CoroutineImpl.kt:54) at kotlinx.coroutines.experimental.DispatchTask.run(CoroutineDispatcher.kt:123) at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1388) at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:251) at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:845) at java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1674) at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1629) at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:108) 12-20 14:46:36.410 26915-26915/I/System.out: after runBlocking1 12-20 14:46:36.410 26915-26915/ I/Choreographer: Skipped 313 frames! The application may be doing too much work on its main thread. 

Если я использую запуск (UI) {} вместо запуска {} , он дает результат, как показано ниже

 12-20 14:57:11.700 27338-27338/ I/System.out: before1 12-20 14:57:11.710 27338-27338/ I/System.out: in async1 12-20 14:57:11.714 27338-27338/ I/System.out: Hello, 12-20 14:57:11.714 27338-27338/ I/System.out: after hello1 12-20 14:57:16.718 27338-27338/ I/art: Note: end time exceeds epoch: 

Он не печатает «Мир», который исходит из другой сопрограммы.

Вот еще один пример runblocking, который использует runblocking из onCreate ()

  println("before runblocking " + Thread.currentThread().id) runBlocking { println("in runblocking " + Thread.currentThread().id) val job = launch(UI) { println("In launch " + Thread.currentThread().id) } println("after launch " + Thread.currentThread().id) } println("after runBlocking " + Thread.currentThread().id) 

Вывод кода выше

 12-20 15:58:13.253 8588-8588/? I/System.out: before runblocking 1 12-20 15:58:13.266 8588-8588/? I/System.out: in runblocking 1 12-20 15:58:13.271 8588-8588/? I/System.out: after launch 1 12-20 15:58:13.273 8588-8588/? I/System.out: after runBlocking 1 12-20 15:58:13.363 8588-8588/? I/System.out: In launch 1 

Как мы и ожидаем, «после runblocking» печатает наконец, но это не так. Если я использую job.join, чтобы дождаться завершения sub coroutine, код

  println("before runblocking " + Thread.currentThread().id) runBlocking { println("in runblocking " + Thread.currentThread().id) val job = launch(UI) { println("In launch " + Thread.currentThread().id) } println("after launch " + Thread.currentThread().id) job.join() // wait until child coroutine completes } println("after runBlocking " + Thread.currentThread().id) 

Вывод кода выше

 12-20 16:10:43.234 9194-9194/ I/System.out: before runblocking 1 12-20 16:10:43.249 9194-9194/ I/System.out: in runblocking 1 12-20 16:10:43.253 9194-9194/ I/System.out: after launch 1 

Тогда каково ожидаемое поведение runblocking ?. Как я могу использовать runblocking?

Несмотря на то, что вы блокируете код, операция mBinding.tvNoDataFound.text = "test" выполняется в рабочем потоке пула.

runBlocking предназначен для того, чтобы runBlocking обычный код блокировки в библиотеки, написанные в стиле приостановки, которые будут использоваться в основных функциях и в тестах.

В вашем случае его не следует использовать. Если вам нужно выполнять фоновые работы, вы никогда не должны блокировать поток пользовательского интерфейса. Это происходит независимо от использования launch или launch(UI) . Последний просто заставляет все работать в одном потоке и блокировать еще до объединения.

Поэтому постарайтесь не блокировать поток пользовательского интерфейса и планировать обновление просмотра позже через launch(UI) или со стандартным View.post {} .