美文网首页
ViewTreeObserver#addOnDrawListen

ViewTreeObserver#addOnDrawListen

作者: sollian | 来源:发表于2019-08-15 17:15 被阅读0次

    在拿到布局后,有时需要给ViewTreeObserver注册一些监听器。今天就碰到一个注册OnDrawListener时发现的系统bug,记录一下。

    问题描述

    在设置布局之后,立即设置OnDrawListener

    代码很简单:

    textView.getViewTreeObserver().addOnDrawListener(new ViewTreeObserver.OnDrawListener() {
        @Override
        public void onDraw() {
        }
    });
    

    api26没有问题,api26以下竟然不会回调!!

    源码排查

    首先看下View#getViewTreeObserver

        public ViewTreeObserver getViewTreeObserver() {
            if (mAttachInfo != null) {
                return mAttachInfo.mTreeObserver;
            }
            if (mFloatingTreeObserver == null) {
                mFloatingTreeObserver = new ViewTreeObserver(mContext);
            }
            return mFloatingTreeObserver;
        }
    

    刚得到View时,还没有mAttachInfo,所以此时返回mFloatingTreeObserver。随后在dispatchAttachedToWindow中:

        void dispatchAttachedToWindow(AttachInfo info, int visibility) {
            mAttachInfo = info;
            ...
            if (mFloatingTreeObserver != null) {
                info.mTreeObserver.merge(mFloatingTreeObserver);
                mFloatingTreeObserver = null;
            }
            ...
    }
    

    注意这个merge方法,问题就出在这里。
    看下api25的源码吧:

        void merge(ViewTreeObserver observer) {
            if (observer.mOnWindowAttachListeners != null) {
                if (mOnWindowAttachListeners != null) {
                    mOnWindowAttachListeners.addAll(observer.mOnWindowAttachListeners);
                } else {
                    mOnWindowAttachListeners = observer.mOnWindowAttachListeners;
                }
            }
    
            if (observer.mOnWindowFocusListeners != null) {
                if (mOnWindowFocusListeners != null) {
                    mOnWindowFocusListeners.addAll(observer.mOnWindowFocusListeners);
                } else {
                    mOnWindowFocusListeners = observer.mOnWindowFocusListeners;
                }
            }
    
            if (observer.mOnGlobalFocusListeners != null) {
                if (mOnGlobalFocusListeners != null) {
                    mOnGlobalFocusListeners.addAll(observer.mOnGlobalFocusListeners);
                } else {
                    mOnGlobalFocusListeners = observer.mOnGlobalFocusListeners;
                }
            }
    
            if (observer.mOnGlobalLayoutListeners != null) {
                if (mOnGlobalLayoutListeners != null) {
                    mOnGlobalLayoutListeners.addAll(observer.mOnGlobalLayoutListeners);
                } else {
                    mOnGlobalLayoutListeners = observer.mOnGlobalLayoutListeners;
                }
            }
    
            if (observer.mOnPreDrawListeners != null) {
                if (mOnPreDrawListeners != null) {
                    mOnPreDrawListeners.addAll(observer.mOnPreDrawListeners);
                } else {
                    mOnPreDrawListeners = observer.mOnPreDrawListeners;
                }
            }
    
            if (observer.mOnTouchModeChangeListeners != null) {
                if (mOnTouchModeChangeListeners != null) {
                    mOnTouchModeChangeListeners.addAll(observer.mOnTouchModeChangeListeners);
                } else {
                    mOnTouchModeChangeListeners = observer.mOnTouchModeChangeListeners;
                }
            }
    
            if (observer.mOnComputeInternalInsetsListeners != null) {
                if (mOnComputeInternalInsetsListeners != null) {
                    mOnComputeInternalInsetsListeners.addAll(observer.mOnComputeInternalInsetsListeners);
                } else {
                    mOnComputeInternalInsetsListeners = observer.mOnComputeInternalInsetsListeners;
                }
            }
    
            if (observer.mOnScrollChangedListeners != null) {
                if (mOnScrollChangedListeners != null) {
                    mOnScrollChangedListeners.addAll(observer.mOnScrollChangedListeners);
                } else {
                    mOnScrollChangedListeners = observer.mOnScrollChangedListeners;
                }
            }
    
            if (observer.mOnWindowShownListeners != null) {
                if (mOnWindowShownListeners != null) {
                    mOnWindowShownListeners.addAll(observer.mOnWindowShownListeners);
                } else {
                    mOnWindowShownListeners = observer.mOnWindowShownListeners;
                }
            }
    
            observer.kill();
        }
    

    其他的监听器都merge了,唯独漏了OnDrawListener。不得不说这是一个悲伤的故事。。

    修补措施

    要解决这个问题,可以通过view.post去注册,因为这时,mAttachInfo已经有值了。

    相关文章

      网友评论

          本文标题:ViewTreeObserver#addOnDrawListen

          本文链接:https://www.haomeiwen.com/subject/nnbzjctx.html