Activity 的setContentView看View的绘制流程
1.Activity.setContentView
public void setContentView(@LayoutRes int layoutResID) {
//获取window = PhoneWindow对象
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
2.进入PhoneWindow.setContentView
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
// 1.初始化DecorView对象,装在各种styleable属性
/**
//2.注入一个用于存子View的mContentRoot容器,再装入DecorView中,为什么这样做?
//我也不太明白,我猜是为了分离DecorView的部分业务吧
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in;
*/
详见2.1
installDecor();
... 省略N行 ...
详见2.2
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
2.1 mContentParent = installDecor();
mContentParent.addView(view, params);
//mContentRoot 被添加进decorView中,而DecorView是一个FrameLayout
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in;
2.2 mContentParent.requestApplyInsets();
//mContentParent是View,此时进入View的requestFitSystemWindows方法,View间接又调起了ViewRootImpl的
3.进入ViewRootImpl
@Override
public void requestFitSystemWindows() {
//初始化时,记录当时的线程,到执行到这里的时候获取当前线程,比较是否是主线程
checkThread();
mApplyInsetsRequested = true;
//准备View绘制流程工作
scheduleTraversals();
}
3.1
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//mTraversalRunnable 是一个runnbale ,run方法执行了
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
3.2 TraversalRunnable
final class TraversalRunnable implements Runnable {
@Override
public void run() {
//开始View绘制流程
doTraversal();
}
}
4.开始 performTraversals ,里面有7百多行代码
private void performTraversals() {
//1.处理LayoutParams相关
//2.处理mAttachInfo相关和相关attachedWindow回调分发和回调
//3.布置宽高
//4. performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
//确认是否需要再次测量,如果在测量过程中,有子View强行不和measureSpec给的有冲突,那就调整再次测量。
//5.performLayout(lp, desiredWindowWidth, desiredWindowHeight);
//6.performDraw()
//7.如果中途有View改变的visibility,则调用前面的scheduleTraversals();重新走流程。
}
伟大的7百行代码,干了很多事情,真能干。从上面的代码可以找出我们View绘制流程中常见的三个方法 performMeasure,performLayout,performDraw ,这三个方法分别各自调用自己的分发过程。在这里就不分析了,网上一大把View的绘制流程。至此,一个Activity就这样降临到你眼前的眼帘,一边看源码一边敲的,做个粗略的笔记。