Window的添加-流程简单梳理版本
前言
当activity生命周期走到onstart,onresume时,activity可见,但是window还不可见,window的绘制在onResume之后,从此处开始进行分析
handleResumeActivity-addView
@Override
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
boolean isForward, boolean shouldSendCompatFakeFocus, String reason) {
... ...
if (r.window == null && !a.mFinished && willBeVisible) {
... ...
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
// 进入addView方法
wm.addView(decor, l);
} else {
// The activity will get a callback for this {@link LayoutParams} change
// earlier. However, at that time the decor will not be set (this is set
// in this method), so no action will be taken. This call ensures the
// callback occurs with the decor set.
a.onWindowAttributesChanged(l);
}
}
... ...
mNewActivities.add(r);
if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r);
Looper.myQueue().addIdleHandler(new Idler());
}
addview方法会调用到WindowManagerImpl,随后调用到WindowManagerGlobal的同名addView方法
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyTokens(params);
mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
mContext.getUserId());
}
WMSImpl-WMSGlobal-addView
在wmsGlobal的addView方法中,new出VRI,然后调用VRI的setView方法
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow, int userId) {
... ...
// new出关键对象ViewRootImpl
if (windowlessSession == null) {
root = new ViewRootImpl(view.getContext(), display);
} else {
root = new ViewRootImpl(view.getContext(), display,
windowlessSession, new WindowlessWindowLayout());
}
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// 关键方法,VRI的setView
// do this last because it fires off messages to start doing things
try {
root.setView(view, wparams, panelParentView, userId);
} catch (RuntimeException e) {
final int viewIndex = (index >= 0) ? index : (mViews.size() - 1);
// BadTokenException or InvalidDisplayException, clean up.
if (viewIndex >= 0) {
removeViewLocked(viewIndex, true);
}
throw e;
}
VRI-setView
此处兵分两路,一路添加窗口,一路绘制窗口
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
int userId) {
synchronized (this) {
... ...
// 关键方法,主要进行绘制
requestLayout();
try {
... ...
//关键方法, 添加窗口
res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId,
mInsetsController.getRequestedVisibleTypes(), inputChannel, mTempInsets,
mTempControls, attachedFrame, compatScale);
... ...
} catch (RemoteException | RuntimeException e) {
... ...
}
}
}
}
addToDisplayAsUser
或许你会好奇,为什么先绘制窗口,后添加窗口,是不是反了,其实执行顺序上,和代码相对位置是相反的,requestLayout内部是一个异步方法,post出去了,
requestLayout
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
scheduleTraversals
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 注意此处同步屏障的使用,阻塞住同步信息,让异步信息的处理被提前
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 此处将会异步执行mTraversalRunnable.run
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
doTraversal
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;
}
}
}
performTraversals
在performTraverslas中进行测绘三部曲,measure-layout-draw
- relayoutWindow
- performMeasure
- performLayout
- performDraw
- createSyncIfNeeded
private void performTraversals() {
... ...
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
... ...
if (!mStopped || mReportNextDraw) {
... ...
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
... ...
}
... ...
performLayout(lp, mWidth, mHeight);
... ...
if (!performDraw(mActiveSurfaceSyncGroup)) {
handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions,
mPendingTransaction, mLastPerformDrawSkippedReason);
mHasPendingTransactions = false;
}
... ...
if (!cancelAndRedraw) {
... ...
createSyncIfNeeded();
... ...
}
... ...
总结
在ActivityThread的handleResumeActivity中,activity处于resume之后,开始了window的绘制,调用addView
然后层层调用到WMSImpl和WMSGlobal的addView方法,该方法new出了VRI,随后去调用VRI的setVIew方法
在VRI的setView方法中
同步执行addToDisplayAsUer添加了窗口,
异步执行了requestLayout准备去测绘->经过schedule/do/perform-Traversals
最终在performTraversals方法中进行了测绘三部曲,measure-layout-draw,绘制完毕
handleResumeActivity
=>performResumeActivity-performResume-执行activity生命周期回调onResume
=>addview(new 出VRI,然后准备调用VRI的setview)
=>setview
异步=>requestLayout();
=>scheduleTraversals
=>doTraversal
=>performTraversals
=>relayoutWindow(方法内调用->relayoutWindowInner->createSurfaceControl-createSurfaceLocked-resetDrawState)对应DRAW_PENDING
=>performMeasure=>performLayout=>performDraw
=>createSyncIfNeeded(方法内调用->reportDrawFinished-finishDrawing-finishDrawingWindow-finishDrawingLocked)对应COMMIT_DRAW_PENDING
同步=>addToDisplayAsUser