Activity,DecorView,PhoneWindow和ViewRoot的作用和相关关系
1,Activity和Window 前者控制生命周期,window控制视图,前者可以没有后者那就相当于一个service,
Activity和Window的第一次邂逅是在ActivityThread调用Activity的attach()函数时。创建一个PhoneWindow
....
mWindow = PolicyManager.makeNewWindow(this);
//当window接收系统发送给它的IO输入事件时,例如键盘和触摸屏事件,就可以转发给相应的Activity
mWindow.setCallback(this);
.....
//设置本地窗口管理器
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
2,Window,Activity和DecorView
DecorView是FragmentLayout 的子类 ,被认为是android 视图树的根节点视图
DecorView作为顶级View 一般包含一个竖向LinearLayout(具体跟android版本和主体有关)上边为标题栏下边为内容
activity 通过setContentView来给 内容栏添加布局内容栏id为content
(ViewGroup)findViewById(R.android.id.content)来得到content对应的layout(在应用层是无法调用R.android的)
结果:Activity的setContentView实际上是调用了Window的setContentView方法。
window生成 Window内部的原始顶级视图(DecorView)添加LinearLayout,style等生成contentParent,把setContentView的view 放入其中contentParent中 就是ContentParent 所显示的视图(呈现给用户的DecorView)为ContentRoot
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) { //[window]如何没有DecorView,那么就新建一个
installDecor(); //[window]
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
....
//[window]第二步,将layout添加到mContentParent
mLayoutInflater.inflate(layoutResID, mContentParent);
.....
}
//[window]创建一个decorView
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor(); //直接new出一个DecorView返回
....
}
if (mContentParent == null) {
//[window] 这一步也是很重要的.
mContentParent = generateLayout(mDecor); //mContentParent是setContentVIew的关键啊
.....
}
....
}
protected ViewGroup generateLayout(DecorView decor) {
// Apply data from current theme.
.......
//[window] 根据不同的style生成不同的decorview啊
View in = mLayoutInflater.inflate(layoutResource, null);
// 加入到deco中,所以应该是其第一个child
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in; //给DecorView的第一个child是mContentView
// 这是获得所谓的content
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
}
.....
return contentParent;
}
那么,Activity中的mDecor是何时被赋值的?我们如何确定它和Widnow中的mDecor指向同一个对象呢?
我们可以查看ActivityThread的 handleResumeActivity 函数,它负责处理Activity的resume阶段。在这个函数中,
Android直接将Window中的DecorView实例赋值给Activity。
3,Window,DecorView 和 ViewRoot
ViewRoot可以被理解为“View树的管理者”——它有一个mView成员变量,它指向的对象和上文中Window和Activity的mDecor指向的对象是同一个对象
ViewRoot对应ViewRootImpl类
它是连接WindowManagerService和DecorView的纽带,View的三大流程(测量(measure),布局(layout),绘制(draw))均通过ViewRoot来完成。
ViewRoot并不属于View树的一份子。从源码实现上来看,它既非View的子类,也非View的父类,但是,它实现了ViewParent接口,这让它可以作为View的名义上的父视图。
RootView继承了Handler类,可以接收事件并分发,Android的所有触屏事件、按键事件、界面刷新等事件都是通过ViewRoot进行分发的
那么,Window是什么时候被添加到WindowManager中的呢?我们回到ActivityThread的handleResumeActivity函数。我们都知道Activity的resume阶段就是要显示到屏幕上的阶段,在Activity也就是DecorView将要显示到屏幕时,系统才会调用addView方法。
// ActivityThread
r.activity.makeVisible();
//Activity
//[windows] DecorView正式添加并显示
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
总结 ActivtyThread调用Activity attach时 创建PhoneWindow,在setcontentview 后 调用PhoneWindow.setcontentview,创建DecorView(Fragment子类,
内含LinearLayout上边标题下内容),将view加入DecorView内容中,当Activity rusume时,也就是ActivityThread的handleResumeActivity函数时会调用makeVisible(),在通过WindowManager 提供的方法交由WindowManagerGloalal 创建RootView(RootViewlmpl)
将decorView add到其列表中(,RootView通过requestLayout 异步刷新并scheduleTraversals绘制视图 通过WindowSession 来完成Window的添加(Wms IPC通讯)
总结 activity>phoneWiddow->DectorView=(titleview(标题)+contentView)>contentView