最近有朋友出去面试,被问到findViewById的原理。
当然,我也不知道,现在就来学习一下。
查看源码,发现不管是activity.findViewById(id),还是view.findViewById(id)最后调用的都是View的findViewById():
@Nullable
public final <T extends View> T findViewById(@IdRes int id) {
if (id == NO_ID) {
return null;
}
return findViewTraversal(id);
}
其中调用了findViewTraversal(),首先来看View的findViewTraversal():
protected <T extends View> T findViewTraversal(@IdRes int id) {
if (id == mID) {
return (T) this;
}
return null;
}
如果要找的id等于当前View的id就返回当前的View,如果不是返回null。
ViewGroup中也重写了这个方法:
protected <T extends View> T findViewTraversal(@IdRes int id) {
// 如果要找的id等于当前View的id就返回当前的View
if (id == mID) {
return (T) this;
}
final View[] where = mChildren;
final int len = mChildrenCount;
// 去遍历自己的子View
for (int i = 0; i < len; i++) {
View v = where[i];
if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
//调用子View的findViewById()
v = v.findViewById(id);
if (v != null) {
return (T) v;
}
}
}
return null;
}
这里面做的操作也很简单,其实就对View树进行遍历。先判断当前节点是不是要找的目标,如果不是再去依次遍历当前节点的子节点,不断循环递归。找到目标就返回,遍历完也没找到,就返回null。
原理很简单,这里记录一下。