Android 12虚拟显示中展示含视频Presentation崩溃问题求助
解决方案
问题根源
Android 12及更高版本对虚拟显示的生命周期回调逻辑做了调整:onDisplayAdded触发时,对应的Display对象可能尚未完全完成初始化,后续可能快速进入不可用状态。原代码依赖onDisplayChanged回调创建Presentation,此时获取的Display可能已经失效,导致调用show()时抛出找不到Display的异常。
修复后的代码
private val mDisplayListener: DisplayManager.DisplayListener = object : DisplayManager.DisplayListener { private var mCurrentDisplayId = -1 private var mPresentation: DataInjection? = null private val mHandler = Handler(Looper.getMainLooper()) override fun onDisplayAdded(displayId: Int) { Log.d(TAG, "onDisplayAdded id=$displayId") // 避免重复处理同一Display if (mCurrentDisplayId == -1) { mCurrentDisplayId = displayId // 延迟执行,给系统足够时间完成Display初始化 mHandler.postDelayed({ createPresentationIfValid(displayId) }, 200) } } override fun onDisplayRemoved(displayId: Int) { Log.d(TAG, "onDisplayRemoved id=$displayId") if (mCurrentDisplayId == displayId) { mCurrentDisplayId = -1 mPresentation?.let { it.dismiss() mPresentation = null } mHandler.removeCallbacksAndMessages(null) } } override fun onDisplayChanged(displayId: Int) { Log.d(TAG, "onDisplayChanged id=$displayId") // 仅在Presentation未创建且Display有效时尝试创建 if (mCurrentDisplayId == displayId && mPresentation == null) { createPresentationIfValid(displayId) } } private fun createPresentationIfValid(displayId: Int) { val display = mDisplayManager?.getDisplay(displayId) // 检查Display是否有效 if (display != null && display.isValid) { try { mPresentation = DataInjection(this@MainActivity, display) mPresentation?.show() } catch (e: WindowManager.BadTokenException) { Log.e(TAG, "Failed to show Presentation: ${e.message}") mPresentation = null mCurrentDisplayId = -1 } } else { Log.w(TAG, "Display $displayId is invalid, skip creating Presentation") mCurrentDisplayId = -1 } } }
关键改动说明
- 延迟初始化:在
onDisplayAdded中通过Handler延迟200ms创建Presentation,给系统足够时间完成虚拟Display的初始化流程 - 有效性检查:创建前调用
display.isValid()验证Display是否处于可用状态,避免使用无效的Display对象 - 异常捕获:捕获
WindowManager.BadTokenException,即使出现异常也能优雅处理,避免应用崩溃 - 状态清理:在
onDisplayRemoved中移除Handler的未执行任务,防止后续无效的创建操作 - 简化状态变量:移除不必要的
mNewDisplayAdded,直接通过mCurrentDisplayId和mPresentation的状态判断逻辑
额外注意事项
- 延迟时间可根据实际设备性能调整,建议在100-300ms之间
- 确保
DataInjection(自定义Presentation)的构造和布局加载逻辑没有阻塞主线程 - 如果虚拟显示是由你的应用创建的,建议在创建虚拟显示的回调中直接获取Display并创建Presentation,而不是依赖DisplayListener,这样能更准确地把握Display的就绪时机
内容的提问来源于stack exchange,提问作者Dorra Gatt
相关产品推荐
相关产品推荐

