https://www.jianshu.com/p/944190c88f97
基础知识
1、ViewRoot:连接器,对应于ViewRootImpl类
连接WindowManager 和 DecorView
完成View的三大流程: measure、layout、draw
/**
* 源码分析:ViewRootImpl.performTraversals()
*/
private void performTraversals() {
// 1. 执行measure流程
// 内部会调用performMeasure()
measureHierarchy(host, lp, res,desiredWindowWidth, desiredWindowHeight);
// 2. 执行layout流程
performLayout(lp, mWidth, mHeight);
// 3. 执行draw流程
performDraw();
}
绘制流程
1、view绘制大致流程分为measure、layout、draw
measure:根据父view传递的 MeasureSpec 进行计算大小
layout:根据measure子view所得到的布局大小和布局参数,将子view放在合适的位置上。
draw:把view绘制到屏幕上
发起绘制到入口:
MeasureSpec:封装了从父view传递到子view到布局要求。每个MeasureSpec代表宽度和高度的要求,每个MeasureSpec都包含了size和mode
EXACTLY:父view已经测量出了子view的大小,对应的是view的layoutparams的match_parent,或者精确数值。
AT_MOST:父容器已经限制了子view的大小,View最终不能大于这个值对应的wrap_content。
UNSPECIFIED:父容器不对子view有任何限制,要多大给多大,这种情况一般用于系统内部,表示一种测量的状态。
view的MeasureSpec 不单单是由父view决定的,根据父view的MeasureSpec和自身的layoutParams一起决定的,
1、初始化 PhoneWindow 和 WindowManager
Activity的attach方法中初始化PhoneWindow,并获取到window manager
mWindow = new PhoneWindow(this, window, activityConfigCallback);
//创建WindowManager
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
mWindowManager = mWindow.getWindowManager();
2、初始化DecorView
activity 的onCreate() -> setContentView()-> getDelegate().setContentView(layoutResID);->
AppCompatDelegateImpl. setContentView()->ensureSubDecor()->createSubDecor()-> mWindow.getDecorView();PhoneWindow.getDecorView()->installDecor()->generateDecor()->new DecorView(context, featureId, this, getAttributes());
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
//创建AppCompatDelegateImpl并调用 setContentView方法
@Override
public void setContentView(@LayoutRes int layoutResID) {
getDelegate().setContentView(layoutResID);
}
AppCompatDelegateImpl中
@Override
public void setContentView(int resId) {
ensureSubDecor();
ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
contentParent.removeAllViews();
LayoutInflater.from(mContext).inflate(resId, contentParent);
mAppCompatWindowCallback.getWrapped().onContentChanged();
}
//获取DecorView
private void ensureSubDecor() {
//没有被加载才会去创建
if (!mSubDecorInstalled) {
//创建DecorView
mSubDecor = createSubDecor();
}
private ViewGroup createSubDecor() {
····
// Now let's make sure that the Window has installed its decor by retrieving it
ensureWindow();
//PhoneWindow.getDecorView()
mWindow.getDecorView();
final LayoutInflater inflater = LayoutInflater.from(mContext);
ViewGroup subDecor = null;
·····
// Now set the Window's content view with the decor
mWindow.setContentView(subDecor);
····
return subDecor;
}
3、ViewRootImpl 的创建和关联 DecorView
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
// mGlobal 是 WindowManagerGlobal 对象的实例
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
mGlobal 是 WindowManagerGlobal 对象的实例,查看它的 addView() 方法
可以看到,ViewRootImpl 是 DecorView 的管理者,它负责 View Tree 的测量、布局和绘制,以及后面会说到的通过 Choreographer 来控制 View Tree 的刷新操作。
4、查看 ViewRootImpl 的 setView 方法:
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
...
// 1、暂时忽略
// 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 {
...
// 2、mWindowSession 通过 Binder 远程调用 WMS 建立联系
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
} catch (RemoteException e) {
...
} finally {
...
}
...
view.assignParent(this);
...
}
}
}
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 设置同步障碍,暂停处理后面的同步消息
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 在下一帧到来的时候执行 mTraversalRunnable
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
...
}
}
设置同步屏障,发送消息
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
// 移除同步障碍
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
...
// 正式进入 View 绘制流程
performTraversals();
...
}
}
private void performTraversals() {
finalView host = mView; // mView 其实就是 DecorView
...
relayoutWindow(params, viewVisibility, insetsPending);
...
// 执行 Measure 流程
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
...
// 执行 Layout 流程
performLayout(lp, desiredWindowWidth, desiredWindowHeight);
...
// 执行 Draw 流程
performLayout();
...
}