在上一篇文章中我们顺延着setContentView()方法查看了一下将自己的布局添加到Window的上面的过程。添加到Window的布局要通过绘制才能显示到界面上,这一章我们就研究一下View的绘制过程。
View的绘制流程
我们先看一下方法调用流程图现在我们看一下源码
View绘制的入口是ActivityThread中的handleResumeActivity方法
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
final Activity a = r.activity;
//activity的onResume调用
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
//获取当前Activity的 window
r.window = r.activity.getWindow();
//获取DecorView
View decor = r.window.getDecorView();
//获取Activity中没mWindowManager
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
wm.addView(decor, l);
}
接下来看看mWindowManager是什么
/** Retrieve the window manager for showing custom windows. */
public WindowManager getWindowManager() {
return mWindowManager;
}
mWindowManager = mWindow.getWindowManager();
上面又调用了mWindow中的getWindowManager(),我们知道Window的唯一子类是PhoneWindow。我们直接去看该类的方法
public WindowManager getWindowManager() {
return mWindowManager;
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
上面的wm指向的是WindowManagerImpl类,接下来看该类中的addView方法
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
wm也是通过WindowManagerGlobal的单例对象调用了他的addView方法
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
省略代码
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
// If this is a panel window, then find the window it is being
// attached to for future reference.
if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
final int count = mViews.size();
for (int i = 0; i < count; i++) {
if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
panelParentView = mViews.get(i);
}
}
}
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
//将view viewRoot params添加到对应的集合中
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// do this last because it fires off messages to start doing things
try {
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
上面的方法创建了ViewRoot 并将root、view、param添加到对应的集合中。并调用ViewRoot的addView方法
/**
* We have one child
*/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
省略代码
requestLayout();
省略代码
}
}
}
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
//检查View更新时是否是在主线程
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
private void performTraversals() {
、、、省略代码
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
、、、省略代码
performLayout(lp, mWidth, mHeight);
、、、省略代码
performDraw();
}
通过上面的一系列的方法最后调用了performMeasure、performLayout、performDraw。上面的三个方法最终调用了当前Activity的DecorView的measure、layout、draw方法。measure方法中会调用onMeasure,layout中会调用onLayout,draw调用了onDraw。
以上就是View绘制的整个过程。目前只记录流程具体细节以后添加。
该文档是自己的学习记录如有错误欢迎指出。