美文网首页
findViewById源码学习

findViewById源码学习

作者: 留给时光吧 | 来源:发表于2018-05-24 20:49 被阅读0次

    findViewById可以说是学习Android开发中最常用的方法了,这里我们就来了解一下这个方法。首先从activity中看:

        public <T extends View> T findViewById(@IdRes int id) {
            return getWindow().findViewById(id);
        }
        public Window getWindow() {
            return mWindow;
        }
    
       mWindow = new PhoneWindow(this, window, activityConfigCallback);
    

    可见最后走的是PhoneWindow中的findViewById方法,进来看一下:

    frameworks\base\core\java\com\android\internal\policy\PhoneWindow.java
    

    但是PhoneWindow中并没有findViewById方法的实现,所以要求他的父类中看:Window

    android\frameworks\base\core\java\android\view\Window.java
    
        public <T extends View> T findViewById(@IdRes int id) {
            return getDecorView().findViewById(id);
        }
    

    看到getDecorView应该就明白是获取的DecorView,他是Activity的顶层视图,这个方法在子类中也就是PhoneWindow实现:

        @Override
        public final View getDecorView() {
            if (mDecor == null || mForceDecorInstall) {
                installDecor();
            }
            return mDecor;
        }
        private DecorView mDecor;
    

    我们再去DecorView 中看一下

    android\frameworks\base\core\java\android\internal\policy\DecorView.java
    

    这里面也没有findViewById方法实现,但是他是继承于FrameLayout的,可以去看看,同样FrameLayout也没有实现,FrameLayout又是继承于ViewGroup,不过ViewGroup也没有实现,那就看ViewGroup的父类:View。终于找到了:

        public final <T extends View> T findViewById(@IdRes int id) {
            if (id == NO_ID) {
                return null;
            }
            return findViewTraversal(id);
        }
    
        protected <T extends View> T findViewTraversal(@IdRes int id) {
            if (id == mID) {
                return (T) this;
            }
            return null;
        }
    

    发现并没有什么用,findViewTraversal中只是将id和自己的id比较,是的话返回自己,否则返回空。看似陷入死胡同了,其实想想也是这样,毕竟VIew代表一个单独控件,没有孩子,寻找一个id最多只能找到自己。所以要去那些有孩子的类中找,既然是从DecorView 过来的,他们又都没有重写findViewById,那么就取父类中找,发现只有ViewGroup中重写了:

        @Override
        protected <T extends View> T findViewTraversal(@IdRes int id) {
            if (id == mID) {
                return (T) this;
            }
    
            final View[] where = mChildren;
            final int len = mChildrenCount;
    
            for (int i = 0; i < len; i++) {
                View v = where[i];
    
                if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
                    v = v.findViewById(id);
    
                    if (v != null) {
                        return (T) v;
                    }
                }
            }
    
            return null;
        }
    

    这里就是findViewById的完整实现了,就是遍历viewgroup的所有孩子,然后递归调用findViewById,知道找到对应的view为止。我们若是在activity中定义,则是从顶层视图开始搜索。

    相关文章

      网友评论

          本文标题:findViewById源码学习

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