在应用中,任何要显示的界面都要依附在Window上,比如Activity、Dialog、Toast都是在window中显示的。Window 是一个抽象类,表示一个窗口,它的具体实现类是 PhoneWindow。实现位于WindowManagerService 中,WindowManagerService位于Android系统架构的Framework层。
Window 分类
Window 有三种类型,分别是应用 Window、子 Window 和系统 Window。应用类 Window 对应一个 Acitivity,子 Window 不能单独存在,需要依附在特定的父 Window 中,比如常见的一些 Dialog 就是一个子 Window。系统 Window是需要声明权限才能创建的 Window,比如 Toast 和系统状态栏都是系统 Window。
Window添加子view
对 Window 的操作是通过 WindowManager 来完成的,WindowManager 是一个接口,它继承自只有三个方法的 ViewManager 接口,包括添加、删除、更新view:
public interface ViewManager{
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
setContentView()在下层调用的就是windowManager的addview()方法。Window内部有叫decorview的根view,将setContentview()传入的view添加到decorvew中,就将view绑定到window中了。
-
setContentView的具体过程
首先去获取getWindow(),返回的是window调attch时创建PhoneWindow对象,调用其setContentView。
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
PhoneWindow中的setContentView方法:
@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.
if (mContentParent == null) {
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 {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
首先mContentParent是一个ViewGroup,我们先对mContentParent进行判空处理,如果为空调用了installDecor()方法,如果mContentParent不为空,那么移除当前ViewGroup的所有子View。
mLayoutInflater在phoneWindow创建的时候被赋值。
public PhoneWindow(Context context) {
super(context);
mLayoutInflater = LayoutInflater.from(context);
}
再看PhoneWindow类中installDecor中部分代码:
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
...
}
mDecor为空则创建一个DecorView,不为空则将当前自己设置给DecorView中的PhoneWindow对象,将inflater引入的view添加到decorView中。