findViewByID原理

144 阅读1分钟

从Activity的findViewById方法进入

@Nullable
public <T extends View> T findViewById(@IdRes int id) {
    return getWindow().findViewById(id);
}

**可以看到进入了Window的findViewById **

@Nullable
public <T extends View> T findViewById(@IdRes int id) {
    return getDecorView().findViewById(id);
}

再是getDecorView的findViewById 顺带贴个图

image.png

点进上面的find方法

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

这边虽然调用的是View的find方法,但是这个getDecorView本质上获取到的是一个ViewGroup,看一下PhoneWindow的源码,调用installDecor,再调generateDecor,最后返回一个DecorView,这个是一个FrameLayout

@Override
public final @NonNull View getDecorView() {
    if (mDecor == null || mForceDecorInstall) {
        installDecor();//这里
    }
    return mDecor;
}
private void installDecor() {
    mForceDecorInstall = false;
    if (mDecor == null) {
        mDecor = generateDecor(-1);//这里
        .....
    } else {
        mDecor.setWindow(this);
    }
    .....
}
protected DecorView generateDecor(int featureId) {
    .....
}

image.png 继续往下就是调用到ViewGroup的findViewById方法,但是ViewGroup中没有find方法,他父类是View,会走View的find方法

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

因为当前是一个ViewGroup,而ViewGroup重写findViewTraversal方法,最后调到ViewGroup的findViewTraversal中

@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;
}

可以看出,这边是循环遍历当前ViewGroup中的子View,然后调用的也是View的find方法,然后View的find方法最后也会调用自身findViewTraversal,View的findViewTraversal方法就是,对比Id,相等就返回

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