窗口管理框架
从上图可以看出,Android的显示系统分为3层:
- UI框架层:负责管理窗口中View组件的布局与绘制以及响应用户输入事件
- WindowManagerService层:负责管理窗口Surface的布局与次序
- SurfaceFlinger层:将WindowManagerService管理的窗口按照一定的次序显示在屏幕上
在Android显示框架里有这么几个角色:
- Activity:应用视图的容器。
- Window:应用窗口的抽象表示,它的实际表现是View。
- View:实际显示的应用视图。
- WindowManagerService:用来创建、管理和销毁Window。
窗口类型
Window 在Android中是一种窗口的概念,他是View的管理者,而WindowManager则是系统Window的管理者
Window在Android中有三种类型:
z-index 是系统Window的层级概念,z-index越大,窗口越位于顶层
- 应用窗口,z-index 在0~99之间
- 子Window,z-index 在1000~1999,不能独立存在,依附于父系统Window,如Dialog
- 系统系统Window,z-index在2000-2999,系统Window,它往往需要声明权限才能创建,如Toast,状态栏,错误提示框
窗口的实现
Window是一个抽象类,它的唯一实现类是PhoneWindow,PhoneWindow里包含了以下内容:
- private DecorView mDecor:DecorView是Activity中的顶级View,它本质上是一个FrameLayout,一般说来它内部包含标题栏和内容栏(com.android.internal.R.id.content)。
- ViewGroup mContentParent:窗口内容视图,它是mDecor本身或者是它的子View。
- private ImageView mLeftIconView:左上角图标
- private ImageView mRightIconView:右上角图标
- private ProgressBar mCircularProgressBar:圆形loading条
- private ProgressBar mHorizontalProgressBar:水平loading条
- 其他的一些和转场动画相关的Transition与listener
setContentView()
我们通常是在Activity里进行调用,但是它的实际实现是在PhoneWindow里。
public class PhoneWindow extends Window implements MenuBuilder.Callback {
@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) {
//1. 如果没有DecorView则创建它,并将创建好的DecorView赋值给mContentParent
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 {
//2. 将Activity传入的布局文件生成View并添加到mContentParent中
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
//3. 回调Window.Callback里的onContentChanged()方法,这个Callback也被Activity
//所持有,因此它实际回调的是Activity里的onContentChanged()方法,通知Activity
//视图已经发生改变。
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
}
这个方法主要做了两件事情:
- 如果没有DecorView则创建它,并将创建好的DecorView赋值给mContentParent
- 将Activity传入的布局文件生成View并添加到mContentParent中
- 回调Window.Callback里的onContentChanged()方法,这个Callback也被Activity所持有,因此它实际回调的是Activity里的onContentChanged()方法,通知Activity视图已经发生改变。
DecorView已经被创建并初始化完毕,Activity里的布局文件也被成功的添加到PhoneWindow的mContentParent(实际上就是DecorView,它是Activity的顶层View)
中,但是这个时候DecorView还没有真正的被WindowManager添加到Window中,它还无法接受用户的输入信息和焦点事件,这个时候就相当于走到了Activity的onCreate()流程,界面还
未展示给用户。
直到走到Activity的onResume()方法,它会调用Activity的makeVisible()方法,DecorView才真正的被用户所看到。
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback, WindowControllerCallback {
/**
* Control whether this activity's main window is visible. This is intended
* only for the special case of an activity that is not going to show a
* UI itself, but can't just finish prior to onResume() because it needs
* to wait for a service binding or such. Setting this to false allows
* you to prevent your UI from being shown during that time.
*
* <p>The default value for this is taken from the
* {@link android.R.attr#windowNoDisplay} attribute of the activity's theme.
*/
public void setVisible(boolean visible) {
if (mVisibleFromClient != visible) {
mVisibleFromClient = visible;
if (mVisibleFromServer) {
if (visible) makeVisible();
else mDecor.setVisibility(View.INVISIBLE);
}
}
}
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
}
还有setContentView是替换View,addContentView是添加View。实现原理相同。