ViewRootImpl细节问题(平常代码根本不会写)

个人感觉,这些东西了解就行,都会了,干脆些源码去算了;
里面有很多就是抄拷贝别人的

1,首次 View 的绘制流程是在什么时候触发的?

答案是在 ActivityThread.handleResumeActivity 里触发的。

public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
        String reason) {

    // ...
    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 {
              // ...
            }
        }

        // If the window has already been added, but during resume
        // we started another activity, then don't yet make the
        // window visible.
    } else if (!willBeVisible) {
        if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
        r.hideForNow = true;
    }
    // ...

}

ActivityThread.handleResumeActivity 里会调用 wm.addView 来添加 DecorView,wm 是 WindowManagerImpl

// WindowManagerImpl
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
// WindowManagerGlobal
public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow) {
    // 这里的 view 就是 DecorView
    // ...
    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) {
        }
    }
}
// ViewRootImpl.setView
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
  requestLayout();
}

最终通过 WindowManagerImpl.addView -> WindowManagerGlobal.addView -> ViewRootImpl.setView -> ViewRootImpl.requestLayout 就触发了第一次 View 的绘制。

ViewRootImpl 创建的时机?

从上面流程里可以看到,ViewRootImpl 也是在 ActivityThread.handleResumeActivity 里创建的。

ViewRootImpl 和 DecorView 的关系是什么?

// ViewRootImpl.setView
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
  requestLayout();
  // ...
  // 这里的 view 是 DecorView
  view.assignParent(this);
}

接着上面的代码看,在 ViewRootImpl.setView 里,通过 DecorView.assignParent 把 ViewRootImpl 设置为 DecorView 的 parent。

所以 ViewRootImpl 和 DecorView 的关系就是 ViewRootImpl 是 DecorView 的 parent。
因为 DecorView 是我们布局的顶层,现在我们就知道层层调用 requestLayout 等方法是怎么调用到 ViewRootImpl 里的了。

Activity、PhoneWindow、DecorView、ViewRootImpl 的关系?

其实上面的问题中,我们经常会说到 PhoneWindow 这个角色,PhoneWindow 其实是 Window 的唯一子类,是 Activity 和 View 交互系统的中间层,而 DecorView 是整个 View 层级的最顶层,ViewRootImpl 是 DecorView 的 parent,但是他并不是一个真正的 View,只是继承了 ViewParent 接口,用来掌管 View 的各种事件,包括 requestLayout、invalidate、dispatchInputEvent 等等。

如何触发重新绘制?

既然上面说到 View 的绘制流程,那我们怎么触发 View 的重新绘制呢?
就是调用 requestLayout 和 invalidate。

requestLayout 和 invalidate 的流程

requestLayout 和 invalidate 的区别

requestLayout 只会触发 measure 和 layout,invalidate 只会触发 draw

你可能感兴趣的:(ViewRootImpl细节问题(平常代码根本不会写))