Dialog不消失之谜——Android窗口系统的"平行宇宙"

在一个叫Android宇宙的世界里,有一个窗口王国,由窗口管理员大人(WindowManagerService) 统治。这个王国分为两个平行世界:

1️⃣ 应用世界(Activity宇宙)

  • 每个Activity都是一栋会倒塌的大楼(生命周期有限)
  • 普通Dialog是楼里的临时展板(依附于大楼)

2️⃣ 系统世界(Global宇宙)

  • 永恒存在的天空之城(系统级空间)
  • 系统Dialog是悬浮飞艇(独立存在)

案件重现:神秘不消失的Dialog

java 复制代码
// 嫌疑人代码片段
public class SystemAppActivity extends Activity {
    private Dialog ghostDialog; // 幽灵对话框
    
    void createGhostDialog() {
        ghostDialog = new Dialog(getApplicationContext()); // 关键点1:使用应用级Context
        
        Window window = ghostDialog.getWindow();
        // 关键点2:开启平行宇宙通道
        window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
        
        ghostDialog.setContentView(R.layout.ghost_dialog);
        ghostDialog.show(); // 飞艇升空
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 大楼倒塌了,但飞艇还在天上飞!
    }
}

解密1:窗口王国的"平行宇宙"法则

宇宙通行证(Token机制)

java 复制代码
// 普通Dialog:使用Activity Token
public class Dialog {
    Dialog(Activity activity) {
        mWindow = new PhoneWindow(activity); // 绑定Activity Token
    }
}

// 系统Dialog:使用系统级Token
void setSystemWindowType() {
    mWindow.setType(TYPE_APPLICATION_OVERLAY); // 激活系统Token
}
通行证类型 绑定对象 生命周期规则
Activity Token 具体Activity 大楼塌=展板毁
系统级Token 全局WindowManager 与任何大楼无关

解密2:窗口管理员的三本登记册

当Activity大楼倒塌时:

java 复制代码
// WMS的清理代码
void removeActivity(IBinder activityToken) {
    // 只查找应用窗口册
    List<Window> appWindows = findWindowsByToken(activityToken);
    for (Window w : appWindows) {
        w.destroy(); // 只销毁普通展板
    }
    // 系统窗口册完全不受影响!
}

解密3:飞艇的永恒能源系统

系统Dialog为何能永生?因为它的能量来源不同:

能源类型 普通Dialog 系统Dialog
动力源 Activity的View树 独立的SurfaceFlinger渲染
控制中心 Activity的WindowManager 全局WindowManagerGlobal
生命周期开关 onDetachedFromWindow 手动dismiss()或系统回收

关键代码证据:

java 复制代码
// SurfaceFlinger 接收渲染指令
void handleMessage(const Message& message) {
    case SYSTEM_WINDOW: // 系统窗口类型
        createIndependentSurface(); // 创建独立渲染层
        break;
    case APP_WINDOW:    // 应用窗口类型
        linkToActivitySurface(); // 链接到Activity
        break;
}

终极解密:平行宇宙的裂缝

当设置了TYPE_APPLICATION_OVERLAY时,发生了维度跃迁:

java 复制代码
// WindowManagerService.java
public int addWindow(...) {
    if (type == TYPE_APPLICATION_OVERLAY) {
        // 进入系统宇宙的裂缝
        mSystemWindows.add(window); 
        attachToSystemSession(); // 绑定到系统会话
        
        // 断开与Activity的连接
        window.disconnectFromActivity();
        return SUCCESS;
    }
    // ...普通窗口处理逻辑
}

这时Dialog获得三大超能力:

  1. 空间穿越:脱离Activity的View树体系
  2. 时间静止:不再响应Activity生命周期
  3. 永恒存在:由全局WindowManager直接管理

案件解决方案

要避免幽灵Dialog,必须手动关闭平行宇宙通道:

java 复制代码
@Override
protected void onDestroy() {
    if (ghostDialog != null) {
        // 关闭维度通道的关键操作
        ghostDialog.dismiss(); 
        
        // 额外防护(Android 8.0+需要)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            ghostDialog.getWindow().setType(TYPE_APPLICATION); // 降维操作
        }
    }
    super.onDestroy();
}

平行宇宙生存法则

场景 正确做法 危险做法
创建系统Dialog 使用Application Context 使用Activity Context
显示时机 检查hasActivity==false时使用 在后台Service直接显示
关闭机制 双保险:onStop+onDestroy关闭 依赖Activity自动关闭
权限管理 动态请求SYSTEM_ALERT_WINDOW 忘记声明权限
内存泄漏防护 WeakReference + 生命周期监听 直接持有Activity引用

💡 宇宙真理:系统级Dialog是"跳出三界外,不在五行中"的存在,获得超能力的同时也失去了Activity的保护伞,开发者必须自己承担管理责任!

相关推荐
用户0273851840263 分钟前
[Android]RecycleView的item用法
android
前行的小黑炭1 小时前
Android :为APK注入“脂肪”,论Android垃圾代码在安全加固中的作用
android·kotlin
帅得不敢出门2 小时前
Docker安装Ubuntu搭建Android SDK编译环境
android·ubuntu·docker
tangweiguo030519872 小时前
Android Kotlin 动态注册 Broadcast 的完整封装方案
android·kotlin
fatiaozhang95272 小时前
浪潮CD1000-移动云电脑-RK3528芯片-2+32G-安卓9-2种开启ADB ROOT刷机教程方法
android·网络·adb·电脑·电视盒子·刷机固件·机顶盒刷机
前行的小黑炭3 小时前
Android 不同构建模式下使用不同类的例子:如何在debug模式和release模式,让其使用不同的类呢?
android·kotlin·gradle
andyguo3 小时前
AI模型测评平台工程化实战十二讲(第一讲:从手工测试到系统化的觉醒)
android
2501_915921433 小时前
小团队如何高效完成 uni-app iOS 上架,从分工到工具组合的实战经验
android·ios·小程序·uni-app·cocoa·iphone·webview
幂简集成4 小时前
通义灵码 AI 程序员低代码 API 课程实战教程
android·人工智能·深度学习·神经网络·低代码·rxjava
2501_916008895 小时前
uni-app iOS 文件管理与 itools 配合实战,多工具协作的完整流程
android·ios·小程序·https·uni-app·iphone·webview