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

Activity.onStop调用WindowManager.addView展示悬浮窗报错如何解决?

问题根因
  • 触发时机问题:Android 7.1及以下版本中,Activity执行onStop回调时,系统已经回收了当前Activity关联的Window token,此时如果悬浮窗使用的是Activity上下文获取的WindowManager,调用addView时就会因为token失效抛出异常
  • 小米ROM适配问题:Redmi 4X搭载的MIUI对后台悬浮窗展示做了额外的权限拦截逻辑,即使Settings.canDrawOverlays返回true,在应用退后台的瞬间添加悬浮窗也会被ROM拦截触发该异常
  • 现有代码的校验逻辑只判断了悬浮窗权限,没有校验当前WindowManager的有效性、以及应用是否处于可添加悬浮窗的状态
修复方案

1. 替换WindowManager的上下文来源

全局使用Application上下文获取WindowManager实例,不要绑定Activity生命周期的上下文,避免token随Activity销毁失效:

// 初始化悬浮窗时用ApplicationContext拿WindowManager
private val windowManager = context.applicationContext.getSystemService(Context.WINDOW_SERVICE) as WindowManager

2. 调整悬浮窗添加的校验逻辑

除了悬浮窗权限校验,额外增加异常捕获、以及View重复添加判断:

fun show() {
    if (!Settings.canDrawOverlays(context.applicationContext)) {
        return
    }
    // 捕获添加过程的异常,避免崩溃
    runCatching {
        if (floatView.parent == null) {
            windowManager.addView(floatView, layoutParams)
        }
    }.onFailure {
        // 异常时可做降级逻辑,比如短延迟重试、记录日志
        it.printStackTrace()
    }
}

3. 调整触发时机

如果业务允许,把悬浮窗触发逻辑从onStop调整为onPause回调,Android 7.1及以下版本中onPause执行时Activity的Window token还未被回收,添加成功率更高:

override fun onPause() {
    super.onPause()
    // 额外判断Activity是否正在销毁
    if (prefsManager.isShowOverlay() && !isFinishing) {
        floatingWindow.show()
    }
}

4. 小米ROM特殊适配

针对小米7.x系统的机型,添加悬浮窗之前额外校验应用是否在前台,退后台后如果需要展示悬浮窗可以延迟500ms再尝试添加,避开ROM的拦截窗口期。

复现说明

自有设备无法复现是因为该问题仅出现在Android 7.0~7.1.2版本的小米定制ROM上,原生Android系统以及更高/更低版本的MIUI都没有这个拦截逻辑。

内容的提问来源于stack exchange,提问作者user924

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.20 06:54:04