View的层级结构

ActivityThread的performLaunchActivity方法

我们知道,在Activity的创建流程中,在ActivityThread的performLaunchActivity方法中调用了Activity的attach方法,在attach方法里创建了PhoneWindow,然后调用setWindowManager给PhoneWindow设置了WindowManager,这是我们需要理解这一切的前提。

public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
        boolean hardwareAccelerated) {
    ...
    if (wm == null) {
        wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
    }
    mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}

public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
    return new WindowManagerImpl(mContext, parentWindow);
}

通过以上,我们记住PhoneWindow的mWindowManager是WindowManagerImpl。

Activity的setContentView方法

在performLaunchActivity方法的最后会回调Activity的onCreate方法,我们知道,在onCreate流程中会创建出PhoneWindow的DecorView:

@Override
 public void setContentView(int layoutResID) {
     if (mContentParent == null) {
         //DecorView的创建
         installDecor();
     } ...
 
     if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
         ...
     } else {
         //自定义xml布局的View加载
         mLayoutInflater.inflate(layoutResID, mContentParent);
     }
     ...
 }
 
 ```
 
*   #### ActivityThread的handleResumeActivity方法
 
 performLaunchActivity流程之后接着会调用handleResumeActivity流程:
@Override
public void handleResumeActivity(IBinder token, ...) {
    ...
    if (r.window == null && !a.mFinished && willBeVisible) {
        r.window = r.activity.getWindow();
        View decor = r.window.getDecorView();
        decor.setVisibility(View.INVISIBLE);
        ViewManager wm = a.getWindowManager();
        WindowManager.LayoutParams l = r.window.getAttributes();
        a.mDecor = decor;
        ...
        if (a.mVisibleFromClient) {
            if (!a.mWindowAdded) {
                a.mWindowAdded = true;
                wm.addView(decor, l);
            } else ...
        }
    } else if ...
        ...
}

```

ViewManager是WindowManager实现的接口,可以看到,这里调用了WindowManager,也就是WindowManagerImpl的addView方法,第一个参数就是要添加的View,也就是DecorView:
@Override
 public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
     ...
     mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
 }
 
 ```
 
 mGlobal是WindowManagerGlobal:
 
 ```
 private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
 
 public static WindowManagerGlobal getInstance() {
     synchronized (WindowManagerGlobal.class) {
         if (sDefaultWindowManager == null) {
             sDefaultWindowManager = new WindowManagerGlobal();
         }
         return sDefaultWindowManager;
     }
 }
 
 ```
 
 可见,Android中所有的界面Window的DecorView都是通过同一个WindowManagerGlobal添加的。
 
*   #### WindowManagerGlobal的addView方法
 
 ```
 public void addView(View view, ViewGroup.LayoutParams params,
         Display display, Window parentWindow) {
     ...
     final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
     ...
     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);
         try {
             root.setView(view, wparams, panelParentView);
         } catch (RuntimeException e) {
             if (index >= 0) {
                 removeViewLocked(index, true);
             }
             throw e;
         }
     }
 }
 
 ```
 
 我们或许在学习过程中都听过ViewRootImpl的名字,原来它是在这里创建的,它的setView方法如下:
 
 ```
 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
     synchronized (this) {
         if (mView == null) {
             mView = view;
                 ...
             mAttachInfo.mRootView = view;
             ...
             mAdded = true;
             ...
             requestLayout();
             ...
             view.assignParent(this);
             ...
         }
     }
 }
 
 ```
 
 可以看到这里调用了requestLayout方法,对于这个方法我们应该有些眼熟,正是这个方法开启了绘制流程,我们下面会讲到。
 
 assignParent方法的意义是什么呢?
 
 ```
 void assignParent(ViewParent parent) {
     if (mParent == null) {
         mParent = parent;
     } else if (parent == null) {
         mParent = null;
     } else {
         throw new RuntimeException("view " + this + " being added, but"
                 + " it already has a parent");
     }
 }
 
 ```
 
 它给View的mParent方法赋值为ViewRootImpl本身,这是为了在View中调用requestLayout方法时可以回调到ViewRootImpl中(我们有时会通过手动调用requestLayout来触发界面的刷新和变化,像setLayoutParams这一类API内部也会调用requestLayout方法来刷新绘制):
 
 ```
 //View中的requestLayout方法
 public void requestLayout() {
     ...
     if (mParent != null && !mParent.isLayoutRequested()) {
         mParent.requestLayout();
     }
     ...
 }
 
 ```
 
 可见,这里会调用mParent,也就是ViewRootImpl的requestLayout方法,这会触发自上而下的绘制流程。
 
*   #### 总结
 
 至此,我们总结一下View的层级结构:
 
 1.  所有的Window(即Activity和Dialog中的PhoneWindow)都有一个ViewRootImpl,这些ViewRootImpl会被放到WindowManagerGlobal的mRoots(一个ArrayList)中保存,WindowManagerGlobal是单例,负责管理所有的ViewRootImpl。
 2.  ViewRootImpl中的mView就是DecorView。
 3.  DecorView中的mContenParent用来盛放我们xml布局中解析加载出的所有View(不在本篇讨论)。
 
 通过上面的分析,我们知道了对于一个Activity来说,它内部持有了一个PhoneWindow,PhoneWindow内部又持有一个DecorView,而在handleResumeActivity流程中,WindowManagerImpl会创建ViewRootImpl,然后把DecorView赋值到它的mView上,DecorView是一个FrameLayout,自定义的xml布局中的根View会被添加到它的mContentParent中,这就是整个View层的结构。

ViewRootImpl的requestLayout方法

@Override
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        checkThread();
        mLayoutRequested = true;
        scheduleTraversals();
    }
}

调用scheduleTraversals方法:

void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        ...
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        ...
    }
}

Choreographer的postCallback方逻辑中不管是走哪一路最终都会走到scheduleVsyncLocked中:

private void scheduleVsyncLocked() {
    mDisplayEventReceiver.scheduleVsync();
}

mDisplayEventReceiver是FrameDisplayEventReceiver实例,scheduleVsync方法的实现在FrameDisplayEventReceiver的父类DisplayEventReceiver中实现:

public void scheduleVsync() {
    ...
    nativeScheduleVsync(mReceiverPtr);
      ...
}

nativeScheduleVsync会绑定屏幕刷新信号,在刷新信号到来时,会执行FrameDisplayEventReceiver的run方法,其中会调用doFrame方法,在doFrame方法中会调用:

doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);

doCallbacks方法中会按照Choreographer.CALLBACK_TRAVERSAL查找mCallbackQueues中的CallbackRecord然后执行它的run方法,CallbackRecord是在前面mChoreographer.postCallback传入的,Choreographer.CALLBACK_TRAVERSAL对应的也就是ViewRootImpl中的mTraversalRunnable:

final class TraversalRunnable implements Runnable {
    @Override
    public void run() {
        doTraversal();
    }
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

可见最终调用的是doTraversal方法,它内部会调用performTraversals方法:

private void performTraversals() {
    // cache mView since it is used so much below...
    final View host = mView;
      ...
    dispatchApplyInsets(host);
    ...
    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
      ...
    performLayout(lp, mWidth, mHeight);
    ...
    performDraw();
    ...
}

performMeasure方法中:

private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
    if (mView == null) {
        return;
    }
    Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
    try {
        mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
}

可以看到从这里进入到DecorView的measure流程,performLayout和performDraw也是同理的逻辑,也就是说三大绘制流程就是在这里依次触发的。