PhoneWindow extends Window
DecorView extends FrameLayout
Activity.setContentView(R.layout.activity_main);
->getWindow().setContentView(layoutResID);
->PhoneWindow.setContentView(layoutResID)
->PhoneWindow.installDecor();
->ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
-> viewGroup.addView(view, params);
首先我们来了解一下我们熟悉的setContentView做了什么?,如上流程,
可以看到我们平常用的setContentView主要是为Window设置DecorView,设置ContentView的子View,至此View Tree构建完毕, 并不是我们通常认为的触发绘制的地方(ContentView,它是一个FrameLayout(android.R.id.content))
我们先来看下面这张图:
1、Activity通过Window来展示内容
2、Window通过ViewRootImpl管理View Tree
下面我们看看是如何触发view绘制的?AMS(ActivityManagerService)
Activity启动时,ActivityThread.handleResumeActivity()方法中建立了decorView与ViewRoot的关联关系,ViewRootImpl.performTraversals()触发了measure,layout,draw流程:
Activity启动
-> ActivityThread.main()
-> ActivityThread.attach(false, startSeq);
-> AMS.attachApplication(mAppThread, startSeq);
-> ActivityThread.bindApplication()
//创建application
-> ActivityThread.handleBindApplication(AppBindData data);
-->Instrumentation.newApplication()
--> Instrumentation.callApplicationOnCreate(app);
-->Application.onCreate()
//创建Activity
-> ActivityThread.handleLaunchActivity()
-->Instrumentation.newActivity()
--> Instrumentation.callActivityOnCreate()
--> Activity.onCreate(icicle, persistentState);
-->Activity.setContentView
//开始绘制View流程
-> ActivityThread.handleResumeActivity()
-> ViewRootImpl.requestLayout()
-> ViewRootImpl的performTraversals()
-> ViewRootImpl.performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
-> ViewRootImpl.performLayout(lp, mWidth, mHeight);
-> ViewRootImpl.performDraw();
1.Measure
measure:
-> ViewRootImpl.performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);//传入performMeasure()方法的MeasureSpec的SpecMode为EXACTLY,SpecSize为窗口尺寸
-> DecorView.measure() -->View.measure(childWidthMeasureSpec, childHeightMeasureSpec)
-> DecorView.onMeasure() -->FrameLayout.onMeasure(int widthMeasureSpec, int heightMeasureSpec)
-> FrameLayout.measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
-> child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
....
->FrameLayout.setMeasuredDimension()
//对于普通View,会调用View类的onMeasure()方法来进行实际的测量工作,该方法的源码如下:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
//View的getDefaultSize()方法对于AT_MOST和EXACTLY这两种情况都返回了SpecSize作为result。
//所以若我们的自定义View直接继承了View类,我们就要自己对wrap_content (对应了AT_MOST)
//这种情况进行处理,否则对自定义View指定wrap_content就和match_parent效果一样了。
public static int getDefaultSize(int size, int measureSpec) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
result = size;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}
2.Layout
layout:
->ViewRootImpl.performLayout(lp, mWidth, mHeight);
->DecorView.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight()); -->View.layout()
->View.setFrame(l, t, r, b);
->DecorView.onLayout(changed, l, t, r, b); -->FrameLayout.onLayout(changed, l, t, r, b);
->FrameLayout.layoutChildren(left, top, right, bottom, false /* no force left gravity */);
->child.layout(childLeft, childTop, childLeft + width, childTop + height);
->View.setFrame(l, t, r, b);
View.layout()
public void layout(int l, int t, int r, int b) {
...
int oldL = mLeft;
int oldT = mTop;
int oldB = mBottom;
int oldR = mRight;
boolean changed = isLayoutModeOptical(mParent) ?
setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
onLayout(changed, l, t, r, b);
...
}
setFrame()方法来设置View的mLeft、mTop、mRight和mBottom四个参数,这四个参数描述了View相对其父View的位置(分别赋值为l, t, r, b),在setFrame()方法中会判断View的位置是否发生了改变,若发生了改变,则需要对子View进行重新布局,对子View的布局是通过onLayout()方法实现的。由于普通View( 非ViewGroup)不含子View,所以View类的onLayout()方法为空。
3.Draw
在onDraw()方法中进行自身的绘制
draw:
-> ViewRootImpl.performDraw();
-> DecorView.draw(Canvas canvas) -->View.draw(Canvas canvas)
-> View.drawBackground(canvas);
-> View.onDraw(canvas);
-> View.dispatchDraw(canvas);
->child.draw(canvas, this, drawingTime);
-> View.onDrawForeground(canvas);
View.draw(Canvas canvas):
View类的onDraw()方法为空,因为每个View绘制自身的方式都不尽相同,对于decorView来说,由于它是容器View,所以它本身并没有什么要绘制的。dispatchDraw()方法用于绘制子View,显然普通View(非ViewGroup)并不能包含子View,所以View类中这个方法的实现为空。
public void draw(Canvas canvas) {
. . .
// 绘制背景,只有dirtyOpaque为false时才进行绘制,下同
int saveCount;
if (!dirtyOpaque) {
drawBackground(canvas);
}
. . .
// 绘制自身内容
if (!dirtyOpaque) onDraw(canvas);
// 绘制子View
dispatchDraw(canvas);
. . .
// 绘制滚动条等
onDrawForeground(canvas);
}
ViewGroup类的dispatchDraw()方法中会依次调用drawChild()方法来绘制子View,drawChild()方法的源码如下:
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
return child.draw(canvas, this, drawingTime);
}