从前文《 源码解析:dialog, popupwindow, 和activity 的第一个view是怎么来的?》中知道了activity第一个view或者说根view或者说mDecorView 其实就是一个FrameLayout,以及是在系统handleResume的时候加入到系统windowManager中的,并由framework中的ViewRootImpl 接管,通过ViewRootImpl.setView() 开始整个显示过程的。这次着重梳理一下view的显示过程(onAttach, onMeasure, onLayout, onDraw )在源码中的过程。
从ViewRootImpl.setview 开始。
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
requestLayout();
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
try {
mOrigWindowType = mWindowAttributes.type;
res = sWindowSession.add(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mAttachInfo.mContentInsets,
mInputChannel);
} catch (RemoteException e) {
mAdded = false;
mView = null;
mAttachInfo.mRootView = null;
mInputChannel = null;
mFallbackEventHandler.setView(null);
unscheduleTraversals();
throw new RuntimeException("Adding window failed", e);
} finally {
if (restore) {
attrs.restore();
}
}在第一次赋值mView的时候,会调用ViewRootImpl.requestLayout();
public void requestLayout() {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}进而scheduleTraversals();
public void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
//noinspection ConstantConditions
if (ViewDebug.DEBUG_LATENCY && mLastTraversalFinishedTimeNanos != 0) {
final long now = System.nanoTime();
Log.d(TAG, "Latency: Scheduled traversal, it has been "
+ ((now - mLastTraversalFinishedTimeNanos) * 0.000001f)
+ "ms since the last traversal finished.");
}
sendEmptyMessage(DO_TRAVERSAL);
}
}进而在handleMessage() 中
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case DO_TRAVERSAL:
performTraversals();
}进而就是performTraversals(),也就是本次分析的重点。
这个函数比较长,不适合把全部函数代码都 贴上来。就分段叙述。
1. 函数刚开始的部分,初始化了一些后面会用到的变量和标志位。
final View host = mView;
WindowManager.LayoutParams lp = mWindowAttributes;
final View.AttachInfo attachInfo = mAttachInfo;
CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
Rect frame = mWinFrame;
mTraversalScheduled = false;
mWillDrawSoon = true;
boolean windowSizeMayChange = false;
boolean fullRedrawNeeded = mFullRedrawNeeded;
boolean newSurface = false;
boolean surfaceChanged = false;
2. 接下来,是一个重要的判断, 如果是初次执行,则调用host.dispatchAttachedToWindow(attachInfo, 0);
if (mFirst) {
// 略去一大堆赋值
mLastConfiguration.setTo(host.getResources().getConfiguration());
host.dispatchAttachedToWindow(attachInfo, 0);
//Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
host.fitSystemWindows(mAttachInfo.mContentInsets);
} else {
desiredWindowWidth = frame.width();
desiredWindowHeight = frame.height();
if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
if (DEBUG_ORIENTATION) Log.v(TAG,
"View " + host + " resized to: " + frame);
fullRedrawNeeded = true;
mLayoutRequested = true;
windowSizeMayChange = true;
}
}在dispatchAttachedToWindow()中重点处理了三件事:
2.1. onAttachedToWindow();
2.2. listener.onViewAttachedToWindow(this);
2.3 onWindowVisibilityChanged(vis);
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
//System.out.println("Attached! " + t