android - 如何在单击按钮时使用运行阻止

标签 android kotlin coroutine kotlinx.coroutines

运行阻塞的目的是什么?我可以在 OnClickListener 中使用它吗? 这里我在 OnClickListener
中使用了 runblocking{} 这是我的代码

 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.

如果我使用 launch(UI){ } 而不是 launch{ },它会给出如下输出

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: 

它不会打印来自另一个协程的“World”。

这是另一个运行阻塞的例子,它使用来自 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

正如我们预期的那样,“after runblocking”最终打印出来了,但实际上并没有。 如果我使用job.join 等待子协程完成,代码是

  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

那么运行阻塞的预期行为是什么?如何使用运行阻止?

最佳答案

即使您阻止了代码,mBinding.tvNoDataFound.text = "test" 操作也会在池工作线程上运行。

runBlocking is designed to bridge regular blocking code to libraries that are written in suspending style, to be used in main functions and in tests.

在您的情况下,不应使用它。如果你需要做后台工作,你不应该阻塞 UI 线程。无论使用 launch 还是 launch(UI),都会发生这种情况。后者只是让所有东西都在同一个线程上运行,甚至在连接之前就阻塞了。

所以尽量不要阻塞 UI 线程,稍后通过 launch(UI) 或使用标准 View.post {} 安排 View 更新.

关于android - 如何在单击按钮时使用运行阻止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47904266/

相关文章:

task - 是否可以保存和恢复 libtask 协程?

python - 为什么在生成器中的 yield 调用周围添加括号允许它编译/运行?

java - Play Billing Library v1.0 订单状态

android - 如何使用 ffmpeg 从应用程序捕获的视频创建视频拼贴?

android - 为什么 imageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);和<应用程序android :hardwareAccelerated ="false" have different effect?

android - 使用 match_parent 和 0dp 作为宽度时,具有 0dp 高度的 ConstraintLayout View 具有不同的实际高度

java - Spring 和 AOP - 处理每个抛出的异常

android - Google Firestore 保存用户输入 Kotlin

java - 如何组合相互依赖的 Observables 并获得一个包含每个值的对象?

python - 将值发送到 Python 协程而不处理 StopIteration