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的保护伞,开发者必须自己承担管理责任!

相关推荐
氦客2 小时前
Android Compose 状态的概念
android·compose·重组·状态·组合·mutablestate·mutablestateof
Jerry2 小时前
Compose 约束条件和修饰符顺序
android
千里马学框架3 小时前
安卓系统中线程优先级Priority查看方式汇总
android·framework·线程·安卓framework开发·优先级·priority
沐怡旸3 小时前
【Android】Handler/Looper机制相关的类图和流程图
android
生莫甲鲁浪戴3 小时前
Android Studio新手开发第二十一天
android·ide·android studio
生莫甲鲁浪戴3 小时前
Android Studio新手开发第二十二天
android·ide·android studio
用户41659673693554 小时前
Jetpack Compose 中实现带圆角边框的单词级富文本效果(分词与布局实践)
android
顾林海4 小时前
Android UI优化:让你的APP从“卡顿掉帧”到“丝滑如德芙”
android·面试·性能优化
啊森要自信4 小时前
【MySQL 数据库】MySQL用户管理
android·c语言·开发语言·数据库·mysql
黄毛火烧雪下4 小时前
(二)Flutter插件之Android插件开发
android·flutter