WebView中的内容闪烁
这类在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 SOFTWARE → HARDWARE 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:
- WebView resumes
- First frame is rendered
- Then hardware acceleration is restored
No arbitrary delay required