Dialog 不消失之谜:一场来自系统底层的 "越狱" 行动

第一章:诡异的现场

小李最近遇到了一件怪事。他在开发一个系统工具类 App 时,给 Dialog 加了一行代码:

java 复制代码
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);

结果发现,当他按 Home 键把 App 切到后台,甚至手动 finish 掉 Activity 时,这个 Dialog 竟然像幽灵一样留在屏幕上!

"这 Dialog 成精了?" 小李盯着屏幕喃喃自语。普通 Dialog 只要 Activity 一销毁就会跟着消失,这个加了特殊 "咒语" 的 Dialog,到底发生了什么?

第二章:侦探登场 ------ 对比实验

为了破解谜团,我们做了两组实验,用代码记录下 Dialog 的 "行为轨迹"。

实验 A:普通 Dialog(乖乖听话型)

java 复制代码
// 普通Dialog的创建过程
Dialog normalDialog = new Dialog(MainActivity.this);
normalDialog.setContentView(R.layout.dialog_normal);
normalDialog.setTitle("我是乖宝宝");

// 显示Dialog
showButton.setOnClickListener(v -> normalDialog.show());

// 销毁Activity的按钮
destroyButton.setOnClickListener(v -> {
    MainActivity.this.finish(); // 销毁Activity
    Log.d("Dialog日志", "Activity已销毁");
});

实验现象:点击销毁按钮后,Activity 消失的同时,普通 Dialog 也跟着不见了。

实验 B:系统级 Dialog(叛逆型)

java 复制代码
// 系统级Dialog的创建过程
Dialog systemDialog = new Dialog(MainActivity.this);
systemDialog.setContentView(R.layout.dialog_system);
systemDialog.setTitle("我要自由");

// 关键咒语:设置系统级窗口类型
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    systemDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
} else {
    systemDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
}

// 显示Dialog(需要先申请悬浮窗权限)
showSystemButton.setOnClickListener(v -> {
    if (Settings.canDrawOverlays(MainActivity.this)) {
        systemDialog.show();
    }
});

// 同样的销毁按钮
destroyButton.setOnClickListener(v -> {
    MainActivity.this.finish();
    Log.d("Dialog日志", "Activity已销毁");
});

实验现象:点击销毁按钮后,Activity 消失了,但系统级 Dialog 依然霸占着屏幕,甚至能在其他 App 上显示!

第三章:线索追踪 ------ 谁在管理 Dialog?

我们把 Android 系统想象成一个大型公寓楼

  • Activity 是一个个住户房间

  • 普通 Dialog 是房间里的家具(衣柜、桌子),必须放在房间里

  • WindowManagerService(WMS) 是公寓管理员,负责管理所有房间和公共区域

  • TYPE_APPLICATION_OVERLAY 是 "公共区域通行证"

普通 Dialog 的 "户口" 挂在 Activity 名下(通过 Context 关联),就像家具的所有权属于房间主人。当房间被拆除(Activity 销毁),管理员 WMS 会通知家具一起被清走。

但加上TYPE_APPLICATION_OVERLAY后,Dialog 相当于办理了 "户口迁移":

  1. 它从 "房间私有财产" 变成了 "公寓公共设施"(比如楼道里的公告栏)
  2. 管理权从房间主人(Activity)移交到了公寓管理员(WMS)
  3. 即使原来的房间拆了(Activity 销毁),只要管理员没收到拆除通知,公告栏就会一直存在

第四章:底层原理 ------ 窗口的 "身份牌"

Android 中所有可见元素都是 "窗口"(Window),每个窗口都有唯一的type属性,这相当于窗口的 "身份牌":

身份牌类型 归属权 生命周期特点
普通应用窗口(默认) 所属 Activity 随 Activity 销毁而销毁
TYPE_APPLICATION_OVERLAY 系统 WMS 独立存在,需手动销毁

当设置TYPE_APPLICATION_OVERLAY后:

  1. Dialog 的窗口被纳入系统窗口管理体系
  2. 它的生命周期不再与创建它的 Activity 绑定
  3. 只有调用dialog.dismiss()或系统重启时,WMS 才会销毁这个窗口
  4. 这也是为什么需要申请SYSTEM_ALERT_WINDOW权限 ------ 系统要限制这种 "不受控" 的窗口

第五章:真相大白

Dialog 不消失的秘密,其实是一场成功的 "权限升级":

  • 普通 Dialog 是 Activity 的 "附属品",主人不在了它就必须离开

  • 系统级 Dialog 通过TYPE_APPLICATION_OVERLAY获得了 "独立居住权",成为系统直接管理的 "常住居民"

就像现实中:如果你在自己店里挂海报(普通 Dialog),店铺关门海报就得取下;但如果你在商场公共区域挂广告牌(系统级窗口),即使你店铺关门了,广告牌只要没到期就会一直挂着。

破案总结

要让系统级 Dialog 乖乖听话,必须手动 "遣散" 它:

java 复制代码
// 在Activity销毁前,主动销毁系统级Dialog
@Override
protected void onDestroy() {
    super.onDestroy();
    if (systemDialog != null && systemDialog.isShowing()) {
        systemDialog.dismiss();
    }
}

从此,小李的 Dialog 再也不会 "闹鬼" 了。这个故事告诉我们:在 Android 世界里,权限决定归属,归属决定命运。

相关推荐
人生游戏牛马NPC1号31 分钟前
学习 Android (二十) 学习 OpenCV (五)
android·opencv·学习
2501_9160088939 分钟前
uni-app iOS 日志与崩溃分析全流程 多工具协作的实战指南
android·ios·小程序·https·uni-app·iphone·webview
文 丰42 分钟前
【AndroidStudio】官网下载免安装版,AndroidStudio压缩版的配置和使用
android
WillWolf_Wang43 分钟前
Linux 编译 Android 版 QGroundControl 软件并运行到手机上
android·linux·智能手机
fatiaozhang95271 小时前
数码视讯TR100-OTT-G1_国科GK6323_安卓9_广东联通原机修改-TTL烧录包-可救砖
android·xml·电视盒子·刷机固件·机顶盒刷机
撬动未来的支点1 小时前
【Android】内核及子系统
android
2501_915921432 小时前
iOS混淆工具实战 在线教育直播类 App 的课程与互动安全防护
android·安全·ios·小程序·uni-app·iphone·webview
前行的小黑炭4 小时前
Android Flow的其他使用:stateIn和冷流(普通Flow)
android·kotlin
tran_sient4 小时前
【Android】制造一个ANR并进行简单分析
android·anr
前行的小黑炭5 小时前
Android Flow:你真的了解?在工作当中的运用~~通过光照例子来解释一下..
android·kotlin