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

Android 12/13动态颜色致弹窗显示时Activity重启崩溃如何修复?

修复Android 12+动态颜色导致Activity重建引发的弹窗崩溃问题

针对你遇到的动态颜色触发Activity重建、弹窗持有旧Activity实例导致WindowLeaked崩溃的问题,以下是几个可行的修复方案:

方案1:让弹窗跟随Activity生命周期自动关闭

  • 给弹窗绑定Activity的生命周期回调,当Activity进入onDestroy状态时,主动关闭弹窗,彻底切断对旧Activity实例的引用。
    • 如果使用DialogFragment,可直接利用其生命周期特性,在onDestroyView方法中调用dismiss()确保弹窗关闭。
    • 如果是自定义弹窗或AlertDialog,在弹窗初始化时给Activity注册ActivityLifecycleCallbacks,在onActivityDestroyed回调里执行弹窗的dismiss();同时用弱引用持有Activity,避免额外内存泄漏。
  • 示例代码片段:
class CustomDialog(private val activityWeakRef: WeakReference<Activity>) {
    private var dialog: AlertDialog? = null

    fun show() {
        val activity = activityWeakRef.get() ?: return
        dialog = AlertDialog.Builder(activity)
            .setMessage("示例弹窗")
            .create()
        dialog?.show()

        // 注册生命周期回调
        activity.registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
            override fun onActivityDestroyed(activity: Activity) {
                dialog?.dismiss()
                activity.unregisterActivityLifecycleCallbacks(this)
            }
            // 实现其他空回调方法
            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
            override fun onActivityStarted(activity: Activity) {}
            override fun onActivityResumed(activity: Activity) {}
            override fun onActivityPaused(activity: Activity) {}
            override fun onActivityStopped(activity: Activity) {}
            override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
        })
    }
}

方案2:用ViewModel保存弹窗状态,重建后恢复

  • 将弹窗的状态(是否显示、内容、用户输入等)存储在ViewModel中,由于ViewModel不受Activity重建影响,能在新Activity实例中读取状态并重建弹窗。
  • 步骤:
    1. 创建自定义ViewModel类,保存弹窗相关状态字段;
    2. 在Activity中初始化ViewModel,显示弹窗时更新状态;
    3. 当Activity重建后,在onCreate方法中检查ViewModel的状态,若需要显示弹窗,用新的Activity实例重新创建并展示。
  • 示例代码片段:
class DialogViewModel : ViewModel() {
    var isDialogShowing = false
    var dialogMessage = ""
}

// 在Activity中
class MainActivity : AppCompatActivity() {
    private val viewModel: DialogViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 重建后恢复弹窗
        if (viewModel.isDialogShowing) {
            showDialog(viewModel.dialogMessage)
        }
    }

    fun showDialog(message: String) {
        viewModel.isDialogShowing = true
        viewModel.dialogMessage = message
        AlertDialog.Builder(this)
            .setMessage(message)
            .setOnDismissListener {
                viewModel.isDialogShowing = false
            }
            .show()
    }
}

方案3:监听壁纸变化,提前关闭弹窗

  • 通过WallpaperManager注册壁纸变化监听器,在壁纸变更触发Activity重建前,主动关闭当前显示的弹窗,避免旧实例被持有。
  • 示例代码片段:
class MainActivity : AppCompatActivity() {
    private var dialog: AlertDialog? = null
    private val wallpaperChangeListener = WallpaperManager.OnWallpaperChangeListener {
        // 壁纸变化时关闭弹窗
        dialog?.dismiss()
    }

    override fun onStart() {
        super.onStart()
        getSystemService(WallpaperManager::class.java).addOnWallpaperChangeListener(wallpaperChangeListener)
    }

    override fun onStop() {
        super.onStop()
        getSystemService(WallpaperManager::class.java).removeOnWallpaperChangeListener(wallpaperChangeListener)
    }

    fun showSampleDialog() {
        dialog = AlertDialog.Builder(this)
            .setMessage("测试弹窗")
            .show()
    }
}

方案4:谨慎使用Application Context创建弹窗(限部分场景)

  • 对于不需要和Activity强绑定的弹窗,可尝试用Application Context创建,但需注意:
    • Android 8.0+需要给弹窗设置TYPE_APPLICATION_OVERLAY类型,同时申请SYSTEM_ALERT_WINDOW权限;
    • 这种弹窗不属于Activity生命周期,不会随Activity重建而关闭,需自行管理其生命周期,避免出现孤儿弹窗。

优先级推荐

优先选择方案1和方案2,它们更符合Android生命周期设计规范,兼容性和稳定性更强;方案3适合需要保留弹窗状态但不想用ViewModel的场景;方案4仅作为特殊场景的补充。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 18:00:27