UI布局绘制入口
代码调用流程图
代码相关思维导图
ActivityThread
在Activity的生命周期中,系统服务AMS会调用到ActivityThread中的handleResumeActivity
方法,在这个方法中,可以看到:
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) {
// ...
// TODO Push resumeArgs into the activity for consideration
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
if (r == null) {
// We didn't actually resume the activity, so skipping any follow-up actions.
return;
}
// ...
if (r.window == null && !a.mFinished && willBeVisible) {
// 获取window
r.window = r.activity.getWindow();
// 获取decor
View decor = r.window.getDecorView();
// 先将decorView设置不可见
decor.setVisibility(View.INVISIBLE);
// 获取windowManager
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
// 设置window的层级
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
// ...
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l);
}
// ...
}
// ...
}
// Get rid of anything left hanging around.
cleanUpPendingRemoveWindows(r, false /* force */);
// The window is now visible if it has been added, we are not
// simply finishing, and we are not starting another activity.
if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
// ...
// 设置decor可见
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();
}
}
// ...
}
- 获取activity中的window;
- 获取window中的decorView并设置为不可见;
- 获取windowManager并调用addView方法添加decorView;
- 添加完毕后,通过activity.makeVisible()设置decorView可见。
WindowManager
我们知道WindowManager
是用来管理view窗口的,它是ViewManager
的子类,它的实现类是WindowManagerImpl
。
public interface WindowManager extends ViewManager {}
public interface ViewManager{
// 添加view
public void addView(View view, ViewGroup.LayoutParams params);
// 更新布局
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
// 移除view
public void removeView(View view);
}
public final class WindowManagerImpl implements WindowManager {
// windowManager中持有一个WindowManagerGlobal单例
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
}
addView
在上面handleResumeActivity
中调用了WindowManager
的addView
方法。在 addView中:
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
// 调用了WindowManagerGlobal中的addView方法
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
在WindowManagerImpl
的addView
中调用了WindowManagerGlobal
中addView
。
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
// ...
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
// If there's no parent, then hardware acceleration for this view is
// set from the application's hardware acceleration setting.
final Context context = view.getContext();
if (context != null
&& (context.getApplicationInfo().flags
& ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
}
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
// ...
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 {
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
mViews保存的是View对象,DecorView
mRoots保存和顶层View关联的ViewRootImpl对象
mParams保存的是创建顶层View的layout参数。
调用root.setView
将参数和视图同时交给了ViewRootImpl
。
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {}
public interface ViewParent {}
ViewRootImpl
setView
/**
* We have one child
*/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
// ...
mAdded = true;
int res; /* = WindowManagerImpl.ADD_OKAY; */
// 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();
// ...
try {
// ...
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(),
mDisplay.getDisplayId(),
mTmpFrame,
mAttachInfo.mContentInsets,
mAttachInfo.mStableInsets,
mAttachInfo.mOutsets,
mAttachInfo.mDisplayCutout, mInputChannel, mTempInsets);
setFrame(mTmpFrame);
} catch (RemoteException e) {
// ...
throw new RuntimeException("Adding window failed", e);
} finally {
if (restore) {
attrs.restore();
}
}
// ...
view.assignParent(this);
// ...
}
}
}
requestLayout
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
scheduleTraversals
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 利用handle回调了 mTraversalRunnable
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
mTraversalRunnable
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
final class TraversalRunnable implements Runnable {
@Override
public void 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
private void performTraversals() {
// ...
if (mFirst || windowShouldResize || insetsChanged ||
viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
mForceNextWindowRelayout = false;
// ...
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);
// ...
// Ask host how big it wants to be
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
// Implementation of weights from WindowManager.LayoutParams
// We just grow the dimensions as needed and re-measure if
// needs be
int width = host.getMeasuredWidth();
int height = host.getMeasuredHeight();
boolean measureAgain = false;
if (lp.horizontalWeight > 0.0f) {
width += (int) ((mWidth - width) * lp.horizontalWeight);
childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
MeasureSpec.EXACTLY);
measureAgain = true;
}
if (lp.verticalWeight > 0.0f) {
height += (int) ((mHeight - height) * lp.verticalWeight);
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
measureAgain = true;
}
if (measureAgain) {
// 进行UI布局的测量
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
}
layoutRequested = true;
}
}
}
// ...
final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
boolean triggerGlobalLayoutListener = didLayout
|| mAttachInfo.mRecomputeGlobalAttributes;
if (didLayout) {
// 进行UI控件的摆放
performLayout(lp, mWidth, mHeight);
// ...
}
// Remember if we must report the next draw.
if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
reportNextDraw();
}
boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
if (!cancelDraw) {
if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).startChangingAnimations();
}
mPendingTransitions.clear();
}
// 进行图形的绘画
performDraw();
} else {
if (isViewVisible) {
// Try again
scheduleTraversals();
} else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).endChangingAnimations();
}
mPendingTransitions.clear();
}
}
mIsInTraversal = false;
}
在performTravals()
中主要调用了performMeasure()
、performLayout()
和performDraw()
来进行UI的测量、布局和绘制。
本文作者:Xiaowu
本文链接:https://jxiaow.gitee.io/posts/cd03afe4/
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
本文链接:https://jxiaow.gitee.io/posts/cd03afe4/
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!