雖然現在都不手寫findViewById,但還是有必要看一下源碼流程。
val tv = findViewById<TextView>(R.id.tv)
AppCompatActivity.findViewById()
public <T extends View> T findViewById(@IdRes int id) {
return getDelegate().findViewById(id);
}
getDelegate()返回AppCompatActivity代理類實例AppCompatDelegateImpl
AppCompatDelegateImpl.findViewById()
public <T extends View> T findViewById(@IdRes int id) {
ensureSubDecor();
return (T) mWindow.findViewById(id);
}
Window.findViewById()
public <T extends View> T findViewById(@IdRes int id) {
return getDecorView().findViewById(id);
}
Window.getDecorView()是個抽象方法,Window實現類PhoneWindow重寫了該方法
PhoneWindow.getDecorView()
private DecorView mDecor;
public final View getDecorView() {
if (mDecor == null || mForceDecorInstall) {
installDecor();
}
return mDecor;
}
DecorView繼承自FrameLayout是個ViewGroup
DecorView.findViewById()--->View.findViewById()
public final <T extends View> T findViewById(@IdRes int id) {
if (id == NO_ID) {
return null;
}
return findViewTraversal(id);
}
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;
}
遍歷調用子View的findViewById(),繼續跟進
View.findViewTraversal()
protected <T extends View> T findViewTraversal(@IdRes int id) {
if (id == mID) {
return (T) this;
}
return null;
}
id == mID則返回此View
流程很簡單。findViewById()方法從Window開始,調用頂層View>DecorView.findViewById()。DecorView是ViewGroup,遍歷調用子View的findViewById(),深度遞歸,直到找到id相同的View。