概述
本文将通过 Dialog 的创建、展示 & 销毁过程 详细说明 「Dialog 的窗口机制」
分析内容
// 1. 创建
Dialog dialog = new ProgressDialog(context);
// 2. 展示
dialog.show();
// 3. 销毁
dialog.cancel();
dialog.dmiss();
Dialog创建
- Dialog一般在Acitivty启动,所以传入的是Activity的Context
- 任何创建方法都是基于Dialog基类,所以下面分析的源码是Dialog基类
// 具体使用
Dialog dialog = new ProgressDialog(context);
// 源码分析
public class Dialog implements DialogInterface, Window.Callback,KeyEvent.Callback, OnCreateContextMenuListener, Window.OnWindowDismissedCallback {
// ...
// 构造函数最终都调运了该默认的构造函数
Dialog(Context context, int theme, boolean createContextThemeWrapper) {
// mContext参数是创建时从外部传入的Activity context对象值
// 步骤1. 获取WindowManager对象
mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
// 步骤2. 为Dialog创建新的Window
Window w = PolicyManager.makeNewWindow(mContext);
mWindow = w;
// 步骤3. 关联WindowManager与新Window
// 注:第二个参数token为null,即一个Window属于Dialog的话,那么该Window的传入的mAppToken对象是null,Dialog没有自己的token
w.setWindowManager(mWindowManager, null, null);
}
......
}
源码说明
- 「步骤1」:因为 context 是Activity,所以获取到的 WindowManager 属于 Activity,所以** Dialog 与 Activity 共用一个 WindowManager 对象**
- 「步骤2」:获得 Activity 的WindowManager对象后,Dialog 又新建了一个 Window对象(PhoneWindow 类型,创建过程类似于 Activity 的 Window 创建过程)
- 「步骤3」:将新创建 Dialog 的 window 关联到 Activity 的 WindowManager。特别注意的是:关于AppToken,只是Window的传入的mAppToken对象是null,但不代表Dialog的window无token,下面会详细说明
重要结论
- 「结论1」:Dialog 与 Activity 共用一个 WindowManager 对象
- 「结论2」:Dialog 拥有自己的窗口 Window(PhoneWindow 类型)
- 「结论3」:Dialog 的 Window 由附属的 Acitivty WindowManager 对象统一管理
Dialog展示
// 具体使用
dialog.show();
// 源码分析
public void show() {
// ....
// 1. 调用 Dialog的onCreate()
dispatchOnCreate(null);
// 2. 调用Dialog的onStart()
onStart();
// 3. 获取当前新Window的DecorView对象(类似于Activity)
mDecor = mWindow.getDecorView();
// 4. 获取新Window的WindowManager.LayoutParams参数
WindowManager.LayoutParams l = mWindow.getAttributes();
// 5. 把一个View添加到与Activity共用的windowManager里
mWindowManager.addView(mDecor, l);
}
源码分析
- 「步骤3」:Dialog获取当前新Window的DecorView对象时过程类似于Activity,所以有一种自定义Dialog布局的方式就是重写Dialog的onCreate方法,使用setContentView传入布局,类似于 Activity。
- 「步骤4」:由于Dialog 与 Activity 共用一个 WindowManager 对象,所以Activity与Dialog共用同一个mAppToken值(只是Dialog和Activity的Window对象不同)。
- 「步骤5」:添加过程与Activity 窗口添加过程 保持一致。
Dialog 销毁
既然添加过程与Activity 窗口添加过程 保持一致,那么不展示 / 销毁过程也是跟Activity 窗口销毁过程 十分类似
// 具体使用
dialog.cancel();
dialog.dmiss();
// 源码分析
// 上述两个方法最终都会回调:dismissDialog()
void dismissDialog() {
//...
mWindowManager.removeViewImmediate(mDecor);
}
mWindowManager 实际上是 WindowManagerImpl 的实例,所以这里的 removeViewImmediate()就是 WindowManagerImpl 中移除 View 的方法,跟Activity 窗口销毁过程 十分类似,这里就不继续展开说明了。
关于Dialog的窗口机制讲解到这里,「Carson每天利用碎片化时间为你解析一个Android知识难点」,长按扫描关注公众号,我们明天见哦!
最后福利:学习资料赠送
- 福利:由本人亲自撰写 & 整理的Android学习方法资料
- 数量:10名
- 参与方式:点击文章右下角”在看“ -> 回复截图到公众号 即可,我将从中随机抽取