正文
另外还给 Window 对象设置了窗口管理器,也就是我们经常用到的 WindowManager 。
WindowManager 是外界接触 Window 的入口,也就是说,想要对 Window 进行一些操作需要用过 WindowManager 来完成。
与DecorView的那些事
在开头中说到,Window 是用来负责管理 View 的。
现在 Window 已经创建完毕了,那么到底什么时候与 View 发生了交集了呢?
我们需要深入到
onCreate()
中一个熟悉的方法:
setContentView(R.layout.activity_main)
。
Activity
setContentView(@LayoutRes int layoutResID)
public void setContentView(@LayoutRes int layoutResID) {
// 这里 getWindow 得到的正是上面创建的 PhoneWindow 对象
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
发现它调用的是 Window 中的同名方法。
接着到 PhoneWindow 中跟进,查看具体实现的逻辑。
PhoneWindow
setContentView(int layoutResID)
@Override
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
// mContentParent 是放置窗口内容的父 viewgroup ,可能是 decorView 本身,也有可能是它的子 viewgroup
// 如果 mContentParent 是空的,那么就说明 decorView 是空的
if (mContentParent == null) {
// 创建 decorview
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
// 将 layout 布局加入到 mContentParent 中并去解析 layout xml 文件
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
// 通知 activity 窗口内容已经发生变化了
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
在
setContentView(int layoutResID)
中,一开始判断了 mContentParent 。mContentParent 其实就是我们设置的 contentView 的父视图。
关于 mContentParent ,在 PhoneWindow 中有注释:
// This is the view in which the window contents are placed. It is either
// mDecor itself, or a child of mDecor where the contents go.
意思就是说,当我们不需要 titlebar 的时候,mContentParent 其实就和 DecorView 一样了;有 titlebar 的时候,DecorView 的内容就分为了 titlebar 和 mContentParent 。
所以如果 mContentParent 为空,那么可以说明还没有创建过 DecorView 。
我们总结一下,在
setContentView(int layoutResID)
中主要就是这三件事:
-
创建 DecorView 视图对象;
-
将自定义的视图 layout_main.xml 进行解析并添加到 mContentParent 中;
-
去通知 activity 窗口视图已经改变了,进行相关操作;
我们去
installDecor()
中看看究竟怎么创建 DecorView 的。
installDecor()
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
// 如果 decorview 为空,调用 generateDecor 来创建 decorview
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
// 创建 mContentParent ,也就是 contentView 的父视图
mContentParent = generateLayout(mDecor);
// Set up decor part of UI to ignore fitsSystemWindows if appropriate.
mDecor.makeOptionalFitsSystemWindows();
final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
R.id.decor_content_parent);
...
}
}
}
在
installDecor()
中,调用了
generateDecor()
方法来创建 DecorView;