文章目录
1.Window
Window是一个抽象类,具体实现是PhoneWindow. Android中所有的视图都是通过Window来呈现的.
每一个Window都对应着一个View和一个ViewRootImpl,Window和View是通过ViewRootImpl来建立联系,Window并不是实际存在的,View才是Window存在的实体.(View不能单独存在,必须依附在Window上)
1.1 Window和WindowManager
WindowManager是外界访问Window的入口,创建一个Window也是通过WindowManager来实现的. WindowManager继承自ViewManager,常用的有三个功能:
- 创建一个Window并向其添加View
- 更新Window中的View
- 删除一个View
1.2 Activity的Window创建过程
Activity的启动过程这里就不过多描述了,最终是由ActivityThread中的performLaunchActivity()
来完成启动过程,并调用attach
方法,在attach
方法中最终会创建PhoneWindow
mWindow = new PhoneWindow(this, window, activityConfigCallback);
2.DecorView
DecorView是一个FrameLayout,是Activity中的顶级View,一般内部包含标题栏和内容栏,但是会随着主题而发生变化;内容栏是一定存在的,完整的id是android.R.id.content;在Activity中通过setContentView()
设置的布局文件就是加载到了内容栏中.
2.1 setContentView源码分析
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
这里的getWindow()
获取的就是在attach方法中创建的PhoneWindow实例,所以我们看一下PhoneWindow的setContentView()
方法
public void setContentView(int layoutResID) {
// 如果mContentParent为空,就去创建一个DecorView
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
//如果不为空,就删除其中的View
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
//把布局文件添加到mContentParent中
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
//回调通知,内容发生改变了
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
这里的mContentParent实际上就是前面提到的id为content
的FrameLayout,这个通过源码可以看出来. 接着看一下 installDecor()
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
mDecor = generateDecor(-1);//创建DecorView
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
//为DecorView设置布局格式,并返回id为content的FrameLayout
mContentParent = generateLayout(mDecor);
......
}
看一下 generateDecor()
protected DecorView generateDecor(int featureId) {
......
return new DecorView(context, featureId, this, getAttributes());
}
就是简单的创建了一个DecorView
而generateLayout()
主要就是先获取主题的样式,然后根据样式加载对应的布局到DecorView中,然后再获取mContentParent并返回,就可以把布局文件添加到mContentParent中了,即Activity所需要展示的布局.
到这为止,Activity的布局文件已经成功添加到了DecorView的mContentParent中,但是DecorView还没有被WindowManager添加到Window中,即用户还不能看到视图.
2.2 DecorView的展示
这里不过多描述Activity的启动过程,在ActivityThread的handleResumeActivity
方法中,首先会调用Activity的onResume方法,接着会调用Activity的makeVisible()
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
到此DecorView真正完成了添加和显示这两个过程,视图就可见了.
我们来看一下addView()
这个方法,WindowManager是个接口,具体实现类是由WindowManagerImpl来实现的
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
......
ViewRootImpl root;
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
......
try {
//将DecorView交给ViewRootImpl
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
}
}
这里实例化了ViewRootImpl对象,然后调用setView()
方法,setView()
经过一系列的处理最终会调用performTraversals()
方法,开始进行View的measure,layout,draw流程,把界面显示出来.
3. ViewRoot
ViewRoot对应于ViewRootImpl类,是连接WindowManager和DecorView的纽带,View的三大流程均是通过ViewRoot来完成的. 在ActivityThread中,Activity对象创建成功后,会将DecorView添加到Window中,同时会创建ViewRootImpl对象,并将ViewRootImpl对象和DecorView建立关联.