WebView中的内容闪烁

移动开发 2026-07-12

这类在setWebViewLayerTypeHardware方法中有一个修复。如果你在onResume中移除修复的安装,即安装软件层的位置,然后在1000毫秒后再安装硬件层,那么当你返回到这个类的屏幕时,WebView的内容会被显示出来。它开始闪烁。如何在不延迟1000毫秒的情况下修复它?如果你立即修改,修复不会消失。我也尝试了在doOnLayout、preDraw、Choreographer上相同的解决方案——也没有帮助。而且我必须使用确切的硬件层

private val isWebViewClearFixEnabled
    get() = features?.getWebViewClearFix()?.isFeatureAvailable() == true

private val isFixEnabled
    get() = features.hasFeatureEnabled()

class CatalogFragment : BaseFragment() {

    private var catalogDelegate: CatalogDelegate? = null
    private var needsGpuReset = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        catalogDelegate = ctalogDelegate(
            shouldCloseOnFinish = arguments?.getBoolean(KEY_CLOSE_ON_FINISH) ?: false,
            closeCatalog = { close() }
        )
        catalogDelegate?.restoreState(savedInstanceState)
        catalogDelegate?.onCreate(requireActivity())
        initMiniAppHandlers()
    }

    override fun onResume() {
        super.onResume()
        setWebViewLayerTypeHardware()
    }

    override fun onPause() {
        super.onPause()
        setWebViewLayerTypeSoftware()
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        giftsCatalogDelegate?.saveState(outState)
    }

    override fun onDestroy() {
        catalogDelegate?.onDestroy(requireContext())
        super.onDestroy()
    }

    private fun setWebViewLayerTypeSoftware() {
        if (isFixEnabled) {
            val webView = browser?.state?.view
            webView?.setLayerType(View.LAYER_TYPE_SOFTWARE, null)
            needsGpuReset = true
        }
    }

    private fun setWebViewLayerTypeHardware() {
        if (isFixEnabled && needsGpuReset) {
            needsGpuReset = false
            val webView = browser?.state?.view ?: return
            // For weak devices 200ms is enough; fast devices empirically need ~1000ms
            webView.postDelayed({
                webView.setLayerType(View.LAYER_TYPE_HARDWARE, null)
            }, 1000)
        }
    }

    // other code
}

解决方案

Your postDelayed(1000) works because it gives the render thread time to recreate the hardware layer. The goal is to wait until the WebView has actually drawn a frame, instead of waiting a fixed time.

What’s happening here is a common WebView GPU context issue on Android. When the fragment pauses and resumes, the GPU layer backing the WebView is not fully restored yet. If you switch from SOFTWAREHARDWARE too early, the surface isn’t ready and the WebView starts flickering or drawing partially.

Cleaner solution is to switch to hardware after the next frame render using ViewTreeObserver or postOnAnimation .

Use postOnAnimation to run after the next frame:

private fun setWebViewLayerTypeHardware() {
    if (isFixEnabled && needsGpuReset) {
        needsGpuReset = false
        val webView = browser?.state?.view ?: return

        webView.postOnAnimation {
            webView.setLayerType(View.LAYER_TYPE_HARDWARE, null)
        }
    }
}

postOnAnimation runs on the next UI frame, which is usually enough for the GPU context to recover.

Even Safer Approach (Wait for First Draw)

If some devices still flicker, switch the layer after the first draw event:

private fun setWebViewLayerTypeHardware() {
    if (isFixEnabled && needsGpuReset) {
        needsGpuReset = false
        val webView = browser?.state?.view ?: return

        webView.viewTreeObserver.addOnDrawListener(object : ViewTreeObserver.OnDrawListener {
            override fun onDraw() {
                webView.viewTreeObserver.removeOnDrawListener(this)
                webView.setLayerType(View.LAYER_TYPE_HARDWARE, null)
            }
        })
    }
}

it ensures:

  1. WebView resumes
  2. First frame is rendered
  3. Then hardware acceleration is restored

No arbitrary delay required

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章