首页 > 解决方案 > 为什么在 SDK 30 及之后,运行 holder.lockCanvas 和 holder.unlockCanvasAndPost 的后台线程仍然会锁定 UI 线程?

问题描述

我有一个简单的 SurfaceView,它使用 Coroutine Dispatcher.Default 范围在后台运行,代码如下

override fun surfaceCreated(holder: SurfaceHolder) {
    doAnimate = true
    job = CoroutineScope(Dispatchers.Default).launch {
        while (doAnimate && isAttachedToWindow) {
            synchronized(holder) {
                val canvas = holder.lockCanvas()
                Thread.sleep(500)
                canvas?.let {
                    drawAnimate.draw(it)
                    holder.unlockCanvasAndPost(it)
                }
            }
        }
    }
}

此代码在 Android SDK 29 及更早版本中运行良好。我仍然可以上下滚动而不会被Sleep如下所示的阻止。

您可以从这里获取实际的应用程序和代码

在此处输入图像描述

从 Android SDK 30 及更高版本开始,绘图仍然有效。但似乎Sleep现在阻塞了 Main.UI 线程,我不能再平滑滚动,即使它Sleep位于协程 Dispatcher.Default 范围(工作线程)后面。

sleep我意识到我可以通过移动外部holder.lockCanvas()holder.unlockCanvasAndPost(it)范围来解决它。

override fun surfaceCreated(holder: SurfaceHolder) {
    doAnimate = true
    job = CoroutineScope(Dispatchers.Default).launch {
        while (doAnimate && isAttachedToWindow) {
            synchronized(holder) {
                val canvas = holder.lockCanvas()
                canvas?.let {
                    drawAnimate.draw(it)
                    holder.unlockCanvasAndPost(it)
                }
                Thread.sleep(500) // <-- Move here
            }
        }
    }
}

Android SDK 30 及更高版本中发生了哪些变化导致了新行为?这是 Android SDK 30 及更高版本中的错误还是新限制?

确实感觉lockCanvasandunlockCanvasAndPost范围现在正在阻塞 UI 线程。真的吗?

标签: androidandroid-canvaskotlin-coroutinessurfaceview

解决方案


推荐阅读