findViewById源碼學(xué)習(xí)

findViewById可以說是學(xué)習(xí)Android開發(fā)中最常用的方法了,這里我們就來了解一下這個方法。首先從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方法,進(jìn)來看一下:

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

但是PhoneWindow中并沒有findViewById方法的實(shí)現(xiàn),所以要求他的父類中看:Window

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

看到getDecorView應(yīng)該就明白是獲取的DecorView,他是Activity的頂層視圖,這個方法在子類中也就是PhoneWindow實(shí)現(xiàn):

    @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方法實(shí)現(xiàn),但是他是繼承于FrameLayout的,可以去看看,同樣FrameLayout也沒有實(shí)現(xiàn),F(xiàn)rameLayout又是繼承于ViewGroup,不過ViewGroup也沒有實(shí)現(xiàn),那就看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;
    }

發(fā)現(xiàn)并沒有什么用,findViewTraversal中只是將id和自己的id比較,是的話返回自己,否則返回空??此葡萑胨篮?,其實(shí)想想也是這樣,畢竟VIew代表一個單獨(dú)控件,沒有孩子,尋找一個id最多只能找到自己。所以要去那些有孩子的類中找,既然是從DecorView 過來的,他們又都沒有重寫findViewById,那么就取父類中找,發(fā)現(xiàn)只有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的完整實(shí)現(xiàn)了,就是遍歷viewgroup的所有孩子,然后遞歸調(diào)用findViewById,知道找到對應(yīng)的view為止。我們?nèi)羰窃赼ctivity中定義,則是從頂層視圖開始搜索。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容