Android Dialog not attached to window manager异常修复方案
问题根因
这个崩溃的核心原因是:你在Fragment的onDestroy生命周期执行dialog.dismiss()时,Dialog对应的DecorView已经和WindowManager解除了绑定关系。此时dialog.isShowing()返回的状态存在滞后性(Dialog内部的显示标记没有随窗口解绑同步更新),调用dismiss()会触发WindowManager查找不存在的窗口视图,最终抛出IllegalArgumentException。
除try/catch外的可行修复方案
- 方案1:提前Dialog的关闭时机,对齐Fragment视图生命周期
不要等到onDestroy才关闭Dialog,把关闭逻辑挪到onDestroyView回调中执行——这个回调是Fragment关联的视图树正式销毁的节点,此时宿主窗口还未完成解绑,不会出现找不到窗口的问题,同时记得执行完关闭后将Dialog实例置空避免内存泄漏:@Override public void onDestroyView() { if(dialog != null && dialog.isShowing()){ dialog.dismiss(); } dialog = null; super.onDestroyView(); } - 方案2:dismiss前增加窗口附着状态校验
不要仅靠isShowing()判断是否可以执行关闭,额外校验Dialog的DecorView是否真实附着在窗口上,只有附着状态下才调用dismiss:if(dialog != null && dialog.isShowing()){ Window dialogWindow = dialog.getWindow(); if (dialogWindow != null) { View decorView = dialogWindow.getDecorView(); if (decorView != null && decorView.isAttachedToWindow()) { dialog.dismiss(); } } } - 方案3:给Dialog绑定生命周期观察者,自动处理关闭
借助AndroidX的Lifecycle能力,给Dialog绑定视图生命周期的观察者,让它在视图销毁节点自动执行关闭,不需要手动在每个生命周期回调里写重复逻辑,注意要使用viewLifecycleOwner的生命周期,避免配置变更(如转屏)场景下的异常:// Dialog初始化完成后添加观察者 getViewLifecycleOwner().getLifecycle().addObserver((LifecycleEventObserver) (source, event) -> { if (event == Lifecycle.Event.ON_DESTROY) { if(dialog != null && dialog.isShowing()){ dialog.dismiss(); } dialog = null; } }); - 方案4:替换为官方封装的DialogFragment实现弹窗
直接弃用手动维护Dialog实例的写法,用DialogFragment实现弹窗。这个组件是官方做了完整生命周期适配的,会自动在宿主生命周期销毁时处理Dialog的dismiss逻辑,配置变更时还能自动恢复弹窗状态,从根源上避免窗口不匹配的崩溃问题,不需要手写任何手动关闭的代码。
内容的提问来源于stack exchange,提问作者Mike Flynn
相关产品推荐
相关产品推荐

