前言
《Android开发艺术探索》第八章介绍WindowManger.LayoutParams的type参数的时候,有这样一句话:子Window不能单独存在,它需要附属在特定的父Window中,比如常见的一些Dialog就是一个子Window。看到这里的时候,我是理解成Dialog属于子Window的。但是,我在昨天看到一篇关于为什么Dialog不能用Application的Context的文章的时候,发现里面说Dialog 的类型是TYPE_APPLICATION,属于应用窗口类型。我就感到奇怪了,那么Dialog到底是属于应用Window还是子Window呢?所以我就从Dialog的源码出发,找寻这个问题的答案,并用这篇文章记录下来。
Dialog
首先看看Dialog的构造方法
Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
//省略无关代码
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
final Window w = new PhoneWindow(mContext);
mWindow = w; //Dialog中的Window其实是一个PhoneWindow
//一些Window的设置
}
从它的构造方法可以看出,Dialog中的Window其实是一个PhoneWindow
然后再看看Dialog的show方法
public void show() {
//省略无关代码
WindowManager.LayoutParams l = mWindow.getAttributes();
//通过PhoneWindow的getAttributes()获取WindowManager.LayoutParams
if ((l.softInputMode
& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
WindowManager.LayoutParams nl = new WindowManager.LayoutParams();
nl.copyFrom(l);
nl.softInputMode |=
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
l = nl;
}
mWindowManager.addView(mDecor, l); //通过WindowManager把自己的Window添加到WMS上
mShowing = true;
sendShowMessage();
}
从show方法可以看到Dialog是通过PhoneWindow的getAttributes()来获取WindowManager.LayoutParams,里面就包含了type参数。所以我们转到看PhoneWindow的getAttributes方法。
Window
由于PhoneWindow并没有重写getAttributes方法,而PhoneWindow是继承于Window的,所以我们直接看Window的getAttributes方法
public final WindowManager.LayoutParams getAttributes() {
return mWindowAttributes;
}
该方法返回mWindowAttributes,我们再看看mWindowAttributes的值
// The current window attributes.
private final WindowManager.LayoutParams mWindowAttributes =
new WindowManager.LayoutParams();
可以看到,这里调用了WindowManager.LayoutParams的无参构造方法
WindowManager.LayoutParams
转到WindowManager.LayoutParams,看看其无参构造方法
public LayoutParams() {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
type = TYPE_APPLICATION;
format = PixelFormat.OPAQUE;
}
注意 type = TYPE_APPLICATION;这句话。到了这里,终于是水落石出了。我们知道了Dialog的type值是TYPE_APPLICATION。
/**
* Window type: a normal application window. The {@link #token} must be
* an Activity token identifying who the window belongs to.
* In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_APPLICATION = 2;
从注释可以看出,该type的值是2,属于应用Window。
总结
从Dialog的构造方法出发,为了确定type的类型,追根溯源一直找到WindowManager.LayoutParams的构造方法。最后发现type的值是TYPE_APPLICATION ,所以我得出结论:由于Dialog的type值是TYPE_APPLICATION,该值属于应用Window的范围,所以Dialog是属于应用Window。如果觉得我这种理解有问题的,或者有什么别的不同理解的,欢迎大家提出来。
参考资料
https://blog.csdn.net/u010375364/article/details/51866330