You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 03:05:27