PS:本文系转载文章,浏览原文可读性会更好,文章开端有原文链接

ps:源码是基于 android api 27 来剖析的

咱们在上一篇文章Android中的ViewTreeObserver剖析(一)列举了一些常见的 ViewTreeObserver外部接口的作用以及剖析了 OnWindowAttachListener 和 OnWindowFocusChangeListener 接口触发机会的过程,这篇文章持续剖析Android中的ViewTreeObserver剖析(一)里列举进去的其余接口的触发工夫的过程。

1、OnGlobalFocusChangeListener 的第一次触发机会

OnGlobalFocusChangeListener 的第一次触发机会是在 View 的布局实现之后 View 的绘制之前进行的,View 的测量、布局和绘制的入口跟踪能够看对Android中View的post办法进行摸索这篇文章;咱们晓得 View 的测量、布局和绘制的入口会调用 ViewRootImpl 的 performTraversals办法;

private void performTraversals() {

    ......    if (didLayout) {        //1、        performLayout(lp, mWidth, mHeight);        ......    }    ......    if (mFirst && sAlwaysAssignFocus) {        ......        if (mView != null) {            if (!mView.hasFocus()) {                //2、                mView.restoreDefaultFocus();                ......            } else {                ......            }        }    }    ......    if (!cancelDraw && !newSurface) {        ......        //3、        performDraw();    } else {        ......    }    ......

}

正文1 中的 performLayout 办法是执行 View 的布局流程;正文3 中的 performDraw办法是执行 View 的绘制流程;正文2 中的 mView 是 DecorView 对象,它的 restoreDefaultFocus 办法是在它的父类的父类中实现,也就是 ViewGroup,咱们看一下 ViewGroup 的 restoreDefaultFocus 办法;

@Overridepublic boolean restoreDefaultFocus() {    ......    //4、    return super.restoreDefaultFocus();}

从正文4 看出,ViewGroup 的 restoreDefaultFocus 办法调用了父类的 restoreDefaultFocus 办法,咱们去看 View 的 restoreDefaultFocus 办法;

public boolean restoreDefaultFocus() {    //5、    return requestFocus(View.FOCUS_DOWN);}

看正文5,View 的 restoreDefaultFocus 办法调用了 View 的 requestFocus(int direction)办法;

public final boolean requestFocus(int direction) {    //6、    return requestFocus(direction, null);}

看正文6,View 的 requestFocus(int direction)办法调用了 requestFocus(int direction, Rect previouslyFocusedRect) 办法,它调用的不是 View 的,而是 ViewGroup 的,因为 ViewGroup 重写了 requestFocus(int direction, Rect previouslyFocusedRect) 办法;

@Overridepublic boolean requestFocus(int direction, Rect previouslyFocusedRect) {    ......    switch (descendantFocusability) {        //7、        case FOCUS_BLOCK_DESCENDANTS:            return super.requestFocus(direction, previouslyFocusedRect);                        //8、        case FOCUS_BEFORE_DESCENDANTS: {            final boolean took = super.requestFocus(direction, previouslyFocusedRect);            return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect);        }                //9、        case FOCUS_AFTER_DESCENDANTS: {            final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);            return took ? took : super.requestFocus(direction, previouslyFocusedRect);        }        ......    }}

正文7 示意拦挡焦点,不论以后 View 是否被聚焦,子 View 肯定获取不到焦点;正文8 示意在子 View 之前判断是否应被聚焦,如果为 false 则会去判断其子 View;正文9 示意在子 View 判断焦点之后判断;咱们以正文7 下的代码为案例,看 super.requestFocus(direction, previouslyFocusedRect) 的具体实现,也就是 View 的 requestFocus(direction, previouslyFocusedRect)办法;

public boolean requestFocus(int direction, Rect previouslyFocusedRect) {    //10、    return requestFocusNoSearch(direction, previouslyFocusedRect);}

看正文10,View 的 requestFocus(direction, previouslyFocusedRect)办法调用了 View 的 requestFocusNoSearch(int direction, Rect previouslyFocusedRect)办法;

private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) {    ......    //11、    handleFocusGainInternal(direction, previouslyFocusedRect);    return true;}

看正文11,View 的 requestFocusNoSearch(int direction, Rect previouslyFocusedRect)办法调用了 View 的 handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) 办法;

void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) {

    ......    if ((mPrivateFlags & PFLAG_FOCUSED) == 0) {        ......        if (mAttachInfo != null) {            //12、            mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this);        }        ......    }

}

看正文12,mAttachInfo.mTreeObserver 是 ViewTreeObserver 类型的对象,View 的 handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) 办法调用了 ViewTreeObserver 的 dispatchOnGlobalFocusChange(View oldFocus, View newFocus) 办法;

final void dispatchOnGlobalFocusChange(View oldFocus, View newFocus) {

    // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to    // perform the dispatching. The iterator is a safe guard against listeners that    // could mutate the list by calling the various add/remove methods. This prevents    // the array from being modified while we iterate it.    final CopyOnWriteArrayList<ViewTreeObserver.OnGlobalFocusChangeListener> listeners = mOnGlobalFocusListeners;    if (listeners != null && listeners.size() > 0) {        for (ViewTreeObserver.OnGlobalFocusChangeListener listener : listeners) {            //13、            listener.onGlobalFocusChanged(oldFocus, newFocus);        }    }

}

看正文13,ViewTreeObserver 的 dispatchOnGlobalFocusChange(View oldFocus, View newFocus) 办法调用了 OnGlobalFocusChangeListener 接口的 onGlobalFocusChanged(View oldFocus, View newFocus) 办法;所以从以上代码的跟踪过程能够得出 OnGlobalFocusChangeListener 的第一次触发机会是在 View 的布局实现之后 View 的绘制之前进行的。

2、OnGlobalLayoutListener 第一次触发机会

OnGlobalLayoutListener 第一次触发机会也是在 View 的布局实现之后 View 的绘制之前进行的,View 的测量、布局和绘制的入口跟踪能够看对Android中View的post办法进行摸索这篇文章;咱们晓得 View 的测量、布局和绘制的入口会调用 ViewRootImpl 的 performTraversals办法;

private void performTraversals() {

    ......    if (didLayout) {        //14、        performLayout(lp, mWidth, mHeight);        ......    }    if (triggerGlobalLayoutListener) {        mAttachInfo.mRecomputeGlobalAttributes = false;        //15、        mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();    }    ......    if (!cancelDraw && !newSurface) {        ......        //16、        performDraw();    } else {        ......    }    mIsInTraversal = false;

}

正文14 中的 performLayout 办法是执行 View 的布局流程;正文16 中的 performDraw办法是执行 View 的绘制流程;正文15 中的 mAttachInfo.mTreeObserver 是 ViewTreeObserver 类型的对象,ViewRootImpl 的 performTraversals办法调用了 ViewTreeObserver 的 dispatchOnGlobalLayout 办法;

public final void dispatchOnGlobalLayout() {

    // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to    // perform the dispatching. The iterator is a safe guard against listeners that    // could mutate the list by calling the various add/remove methods. This prevents    // the array from being modified while we iterate it.    final CopyOnWriteArray<ViewTreeObserver.OnGlobalLayoutListener> listeners = mOnGlobalLayoutListeners;    if (listeners != null && listeners.size() > 0) {        CopyOnWriteArray.Access<ViewTreeObserver.OnGlobalLayoutListener> access = listeners.start();        try {            int count = access.size();            for (int i = 0; i < count; i++) {                //17、                access.get(i).onGlobalLayout();            }        } finally {            listeners.end();        }    }

}

看正文17,access.get(i) 示意的是 OnGlobalLayoutListener 接口对象,所以正文17 这里回调了 OnGlobalLayoutListener 接口的 onGlobalLayout 办法,所以 OnGlobalLayoutListener 第一次触发机会也是在 View 的布局实现之后 View 的绘制之前进行的。

3、OnPreDrawListener 第一次触发机会

OnPreDrawListener 第一次触发机会是在 View 的布局实现之后 View 的绘制之前进行的,咱们晓得 View 的测量、布局和绘制入口会调用 ViewRootImpl 的 performTraversals 办法;

private void performTraversals() {

    ......    if (didLayout) {        //18、        performLayout(lp, mWidth, mHeight);        ......    }    ......    //19、    boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;    if (!cancelDraw && !newSurface) {        ......        //20、        performDraw();    } else {        if (isViewVisible) {            // Try again            //21、            scheduleTraversals();        } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {            ......        }    }    mIsInTraversal = false;

}

正文18 中的 performLayout 办法是执行 View 的布局流程;正文20 中的 performDraw办法是执行 View 的绘制流程;当正文19 中的 cancelDraw 为 true 时,isViewVisible 变量也为 true 时,就会调用正文21 中的 scheduleTraversals 办法,scheduleTraversals 办法还是会间接调用到 ViewRootImpl 的 performTraversals 办法;cancelDraw 和 isViewVisible 变量都为 true,可能拦挡正文20 中的 performDraw 办法,从新发动测量、布局和绘制流程,也就是会间接调用 ViewRootImpl 的 performTraversals 办法;正文19 中的 mAttachInfo.mTreeObserver 是 ViewTreeObserver 类型的对象,咱们且看正文19 中的 ViewTreeObserver 中的 dispatchOnPreDraw 办法;

public final boolean dispatchOnPreDraw() {

    boolean cancelDraw = false;    final CopyOnWriteArray<ViewTreeObserver.OnPreDrawListener> listeners = mOnPreDrawListeners;    if (listeners != null && listeners.size() > 0) {        CopyOnWriteArray.Access<ViewTreeObserver.OnPreDrawListener> access = listeners.start();        try {            int count = access.size();            for (int i = 0; i < count; i++) {                //22、                cancelDraw |= !(access.get(i).onPreDraw());            }        } finally {            listeners.end();        }    }    return cancelDraw;

}

看到正文22 没,access.get(i) 是 OnPreDrawListener 接口,ViewTreeObserver 中的 dispatchOnPreDraw 办法最终调用了 OnPreDrawListener 的 onPreDraw 办法;所以 OnPreDrawListener 第一次触发机会是在 View 的布局实现之后 View 的绘制之前进行的。

4、OnDrawListener 第一次触发机会

OnDrawListener 第一次触发机会是在 View 的绘制过程,咱们先从 ViewRootImpl 的 performTraversals 办法看起;

private void performTraversals() {

    ......    if (!cancelDraw && !newSurface) {        ......        //23、        performDraw();    } else {       ......    }    mIsInTraversal = false;

}

看正文23,performDraw 办法是进行 View 的绘制流程,performTraversals 办法调用了 ViewRootImpl 的 performDraw 办法;

private void performDraw() {

    ......    try {        //24、        draw(fullRedrawNeeded);    } finally {        ......    }    ......

}

看正文24,performDraw 办法调用了 ViewRootImpl 的 draw(boolean fullRedrawNeeded) 办法;

private void draw(boolean fullRedrawNeeded) {

    ......    //25、    mAttachInfo.mTreeObserver.dispatchOnDraw();    ......

}

看正文25,mAttachInfo.mTreeObserver 是 ViewTreeObserver 类型的对象,ViewRootImpl 的 draw(boolean fullRedrawNeeded) 办法调用了 ViewTreeObserver 的 dispatchOnDraw 办法;

public final void dispatchOnDraw() {

    if (mOnDrawListeners != null) {        mInDispatchOnDraw = true;        final ArrayList<ViewTreeObserver.OnDrawListener> listeners = mOnDrawListeners;        int numListeners = listeners.size();        for (int i = 0; i < numListeners; ++i) {            //26、            listeners.get(i).onDraw();        }        mInDispatchOnDraw = false;    }

}

看正文26,listeners.get(i) 是 OnDrawListener 接口,ViewTreeObserver 的 dispatchOnDraw 办法调用了 OnDrawListener 的 onDraw 办法,OnDrawListener 的 onDraw 办法告诉 View 开始绘制,所以OnDrawListener 第一次触发机会是在 View 的绘制过程。

5、OnTouchModeChangeListener 第一次触发机会

OnTouchModeChangeListener 第一次触发机会是在 View 的绘制完之后,OnTouchModeChangeListener 第一次触发机会是跟 OnWindowFocusChangeListener 的触发机会的流程大部分是一样的,OnWindowFocusChangeListener 的触发机会能够看Android中的ViewTreeObserver剖析(一)这篇文章,从Android中的ViewTreeObserver剖析(一)这篇文章能够看出 OnWindowFocusChangeListener 的触发机会的过程中会调用 ViewRootImpl 的外部类 ViewRootHandler 的 case MSG_WINDOW_FOCUS_CHANGED 的代码;

final class ViewRootHandler extends Handler {

    ......    @Override    public void handleMessage(Message msg) {        switch (msg.what) {            ......            case MSG_WINDOW_FOCUS_CHANGED: {                if (mAdded) {                    ......                    if (hasWindowFocus) {                        boolean inTouchMode = msg.arg2 != 0;                        //28、                        ensureTouchModeLocally(inTouchMode);                        ......                    }                    ......                    if (mView != null) {                        ......                        //29、                        mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);                        ......                    }                    ......                }            } break;            ......        }    }

}

正文29 的代码最终会调用 OnWindowFocusChangeListener 接口;看正文 28处的代码,ViewRootHandler 的 case MSG_WINDOW_FOCUS_CHANGED 的代码又调用了 ViewRootImpl 的 ensureTouchModeLocally(boolean inTouchMode) 办法;

private boolean ensureTouchModeLocally(boolean inTouchMode) {

    ......    //30、    mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);    return (inTouchMode) ? enterTouchMode() : leaveTouchMode();

}

看正文30 的代码,mAttachInfo.mTreeObserver 是 ViewTreeObserver 类型的对象,ViewRootImpl 的 ensureTouchModeLocally(boolean inTouchMode) 办法调用了 ViewTreeObserver 的 dispatchOnTouchModeChanged(boolean inTouchMode) 办法;

final void dispatchOnTouchModeChanged(boolean inTouchMode) {

    final CopyOnWriteArrayList<ViewTreeObserver.OnTouchModeChangeListener> listeners =            mOnTouchModeChangeListeners;    if (listeners != null && listeners.size() > 0) {        for (ViewTreeObserver.OnTouchModeChangeListener listener : listeners) {            //31、            listener.onTouchModeChanged(inTouchMode);        }    }

}

看正文31,listener 是 OnTouchModeChangeListener 接口,ViewTreeObserver 的 dispatchOnTouchModeChanged(boolean inTouchMode) 办法调用了 OnTouchModeChangeListener 的 onTouchModeChanged(boolean isInTouchMode) 办法;从以上代码跟踪来看,所以 OnTouchModeChangeListener 第一次触发机会是在 View 的绘制完之后。

6、OnScrollChangedListener 第一次触发机会

OnScrollChangedListener 第一次触发机会是 View 的绘制过程,它的触发过程有一部分跟 OnDrawListener 第一次触发机会(小标题4的内容)一样(ViewRootImpl.performTraversals()->ViewRootImpl.performDraw()->ViewRootImpl.draw(boolean fullRedrawNeeded)),都会被 ViewRootImpl 的 draw(boolean fullRedrawNeeded) 办法被调用;

private void draw(boolean fullRedrawNeeded) {

    ......    if (mAttachInfo.mViewScrollChanged) {        mAttachInfo.mViewScrollChanged = false;        //32、        mAttachInfo.mTreeObserver.dispatchOnScrollChanged();    }    ......    //33、    mAttachInfo.mTreeObserver.dispatchOnDraw();    ......

}

正文33 的代码最终会调用 OnDrawListener 接口的办法;看正文32,mAttachInfo.mTreeObserver 是 ViewTreeObserver 类型的对象,ViewRootImpl 的 draw(boolean fullRedrawNeeded) 办法也会调用到 ViewTreeObserver 的 dispatchOnScrollChanged 办法;

final void dispatchOnScrollChanged() {

    // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to    // perform the dispatching. The iterator is a safe guard against listeners that    // could mutate the list by calling the various add/remove methods. This prevents    // the array from being modified while we iterate it.    final CopyOnWriteArray<ViewTreeObserver.OnScrollChangedListener> listeners = mOnScrollChangedListeners;    if (listeners != null && listeners.size() > 0) {        CopyOnWriteArray.Access<ViewTreeObserver.OnScrollChangedListener> access = listeners.start();        try {            int count = access.size();            for (int i = 0; i < count; i++) {                //34、                access.get(i).onScrollChanged();            }        } finally {            listeners.end();        }    }

}

看正文34,access.get(i) 是 OnScrollChangedListener 接口,ViewTreeObserver 的 dispatchOnScrollChanged 办法调用了 OnScrollChangedListener 的 onScrollChanged 办法,所以从下面代码跟踪得出,OnScrollChangedListener 第一次触发机会是 View 的绘制过程。