在上一篇文章中,我们分析了View的添加流程,这里我们在分析View是如何绘制的。
在ActivityThread类中,Activity的启动会调用handleResumeActivity()方法(ps:这里不对Activity的启动流程作分析),在该方法中,会调用 wm.addView(decor, l);方法,这里其实是将DecorView添加至Window窗口上。
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
//...
//...
//...
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
//...
//...
//...
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
//注释1 这里是将DecorView添加至Window窗口上
wm.addView(decor, l);
} else {
a.onWindowAttributesChanged(l);
}
}
} else if (!willBeVisible) {
if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
}
//...
//...
//...
}
wm是一个WindowManager对象,翻看源码得知wm是WindowManagerImpl对象
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated
|| SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
//这里就是wm对象
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
进入WindowManagerImpl,找到注释1中的addView()方法,发现其调用了 mGlobal.addView()方法
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
进入mGlobal.addView()方法,在注释2中,创建了ViewRootImpl对象root,并给传递的view对象设置LayoutParams,最终调用 root.setView()方法,将view添加给root对象
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
//...
//...
//...
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
// Start watching for system property changes.
if (mSystemPropertyUpdater == null) {
mSystemPropertyUpdater = new Runnable() {
@Override public void run() {
synchronized (mLock) {
for (int i = mRoots.size() - 1; i >= 0; --i) {
mRoots.get(i).loadSystemProperties();
}
}
}
};
SystemProperties.addChangeCallback(mSystemPropertyUpdater);
}
//...
//...
//...
int index = findViewLocked(view, false);
if (index >= 0) {
if (mDyingViews.contains(view)) {
// Don't wait for MSG_DIE to make it's way through root's queue.
mRoots.get(index).doDie();
} else {
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
// The previous removeView() had not completed executing. Now it has.
}
//注释2
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// do this last because it fires off messages to start doing things
try {
//注释3
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
这里我们进入 root.setView()方法,发现其调用了requestLayout();方法,这里代码比较长,就不贴了。
进入requestLayout();
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
checkThread();方法中只做了一件事,核实是否为UI线程
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
进入scheduleTraversals()方法,这里启用了TraversalRunnable线程对象,在run()方法中执行了doTraversal()方法,我们继续进入doTraversal()方法,
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
这里调用了performTraversals()方法,进入该方法,该方法代码量比较多,在这里我们发现View绘制的三大步,测量、布局、绘制,即注释4、注释5、注释6,由此我们得知View绘制流程:onMeasure、onLayout、onDraw
private void performTraversals() {
//...
//...
//...
if (!mStopped || mReportNextDraw) {
boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
(relayoutResult & WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
|| mHeight != host.getMeasuredHeight() || contentInsetsChanged ||
updatedConfiguration) {
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
//注释4
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
}
}
//...
//...
//...
final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
if (didLayout) {
//注释5
performLayout(lp, mWidth, mHeight);
}
//...
//...
//...
boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
if (!cancelDraw && !newSurface) {
//注释6
performDraw();
} else {
//...
//...
//...
}
}
至此,View的绘制流程完毕。