View的绘制流程
View的绘制流程分析
1、首先从Activty 的生命周期开始setContentVie()开始。在activity的setContentView 方法里面如:
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
调用的是phoneWindow.setContentView(@LayoutRes int layoutResID) 方法:
@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.
//一开始mContactParent 是为null的,因此会先初始化DecorVIew
if (mContentParent == null) {
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 {
//将layout 解析并add 到mContentParent中
mLayoutInflater.inflate(layoutResID, mContentParent);
}ontentParent.addView(view, params);
}
...
主要关注installDecor(),
private void installDecor() {
if (mDecor == null) {
// new 一个Decorview 的对象
mDecor = generateDecor(-1); //1
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
.....
if (mContentParent == null) {
mContentParent = generateLayout(mDecor); //②
首先会先执行会上面的方法1, new 了一个Decorview的对象,而DecorView则是PhoneWindow类的一个内部类,继承于FrameLayout,由此可知它也是一个ViewGroup,那么DecorView起到什么作用呢?
其实DecorView 是viewTree里的顶层View,是继承FrameLayout 的,有标题view和内容view这两个子元素,而内容view则是上面提到的mContentParent。我们接着看②号代码获取对应的mConentParent对应的View .
protected ViewGroup generateLayout(DecorView decor) {
...
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
...
其中ID_ANDROID_CONTENT = com.android.internal.R.id.content; 对应我们的内容view 中,这个view 就是用来填充我们之前setContantView 方法传过来的layout 对应的view.
现在会回到之前的phoneWindow.setContentView() 在installDecor 后会通过LayoutInflate.infalte 将传过来的layout解析成view 并添加到mContentParent 中。
2、接下来到Activity 的onResume()阶段。 android 都是消息驱动的, activity 的onResume 也是有消息驱动的,在ActiviAtyThread 收到onResume的消息会调用
ActivityThread 里面的handleResumeAcivity , 那么就到了acitivty 生命周期里的onResume 阶段 , 所以activity 里的view 渲染都是在onResume 阶段。
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
ActivityClientRecord r = mActivities.get(token);
...
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l);
...
在这个阶段会通过windowManager 将onCreate 创建的DecorView add 进去 。WindouwManager 的实现类是WindowManagerImpl如:
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
接下来调用到WindowManagerGlobal.addView 方法:
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
....
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
...
try {
root.setView(view, wparams, panelParentView);
}
...
在这里构造了ViewRootImpl类 .继续看root.setView 方法。
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
mAttachInfo.mDisplayState = mDisplay.getState();
mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
....
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
requestLayout();
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
....
接下来来调用了requestLaout 方法
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
if (ViewDebugManager.DEBUG_REQUESTLAYOUT) {
Log.d(mTag, "requestLayout: mView = " + mView + ", this = " + this,
new Throwable("requestLayout"));
}
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
在scheduleTraversals 里面将CALLBACK_TRAVERSAL 消息push (mChoreographer.postCallback) 到一个Choreographer的一个队列里面。
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
if (ViewDebugManager.DEBUG_SCHEDULETRAVERSALS) {
Log.v(mTag, "scheduleTraversals: mTraversalBarrier = " + mTraversalBarrier
+ ",this = " + this, new Throwable("scheduleTraversals"));
}
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
在Choreographer 在将CALLBACK_TRAVERSAL 这种类型的数据放到队列的同时会通知Choreographer 的FrameDisplayEventReceiver 接受surfaceflinger 上传的Vsync 信号,收到后执行doFrame方法,最后会执行到TraversalRunnable 的run()方法,执行doTraversal 操作。
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
void doTraversal() {
if (ViewDebugManager.DEBUG_LIFECYCLE || ViewDebugManager.DEBUG_ENG) {
Log.v(mTag, "doTraversal: mTraversalScheduled = " + mTraversalScheduled + " mFisrt = "
+ mFirst + ",mTraversalBarrier = " + mTraversalBarrier + ",this = " + this);
}
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
doTraversal 主要调用了performTraversals()方法,在该方法里面分布调用performMeasure,performLayout,performDraw 分布完成view 的测量,布局,和绘制操作。
private void performTraversals() {
// cache mView since it is used so much below...
final View host = mView;
...
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
...
performLayout(lp, mWidth, mHeight);
...
performDraw();
...
到了上面的流程后,就是对于的view 的测量,布局,和绘制操作流程分析了。 下一节分析ViewGroup的绘制流程

浙公网安备 33010602011771号