findViewById源码学习

2018-05-24  本文已影响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中定义,则是从顶层视图开始搜索。

上一篇下一篇

猜你喜欢

热点阅读