歡迎訪問(wèn)[Android日記](méi)[1],如有轉(zhuǎn)載請(qǐng)注明Android日記 http://androiddiary.site
2017.1.10 周二 晴 臨沂
寫(xiě)日記
從findViewById()說(shuō)
還記得三年之前學(xué)習(xí)android就開(kāi)始使用findViewById,但是用了這么久還沒(méi)有具體分析過(guò)他的實(shí)現(xiàn),今天終于有機(jī)會(huì)仔細(xì)看看魔种。
- 在Activity中找到findViewById方法
/**
* Finds a view that was identified by the id attribute from the XML that
* was processed in {@link #onCreate}.
*
* @return The view if found or null otherwise.
*/
public View findViewById(@IdRes int id) {
return getWindow().findViewById(id);
}
- getWindow:
public Window getWindow() {
return mWindow;
}
mWindow 是 private Window mWindow; 是一個(gè)Window類(lèi)型的變量
- 再看Window類(lèi)中的findViewById方法
/**
* Finds a view that was identified by the id attribute from the XML that
* was processed in {@link android.app.Activity#onCreate}. This will
* implicitly call {@link #getDecorView} for you, with all of the
* associated side-effects.
*
* @return The view if found or null otherwise.
*/
@Nullablepublic View findViewById(@IdRes int id) {
return getDecorView().findViewById(id);
}
發(fā)現(xiàn)getDecorView()是Window中的一個(gè)抽象方法。而Window唯一的子類(lèi)是PhoneWindow.
在PhoneWindow找到getDecorView()方法
@Override
public final View getDecorView() {
if (mDecor == null || mForceDecorInstall) {
installDecor();
}
return mDecor;
}
而mDecor是Phone的一個(gè)內(nèi)部類(lèi)DecorView
private final class DecorView extends FrameLayout implements RootViewSurfaceTaker
它繼承了FrameLayout ,而FrameLayout 是ViewGroup的子類(lèi)
- 最終我們?cè)赩iew類(lèi)中找到了
/**
* Look for a child view with the given id. If this view has the given
* id, return this view.
*
* @param id The id to search for.
* @return The view that has the given id in the hierarchy or null
*/
@Nullablepublic final View findViewById(@IdRes int id) {
if (id < 0) {
return null;
}
return findViewTraversal(id);
}
在View類(lèi)的findViewById中調(diào)用的方法findViewTraversal只在ViewGroup里面被重寫(xiě)(Override)了势誊。
我們先看一下ViewGroup中的實(shí)現(xiàn)(因?yàn)閙Decor是ViewGroup的子類(lèi)會(huì)調(diào)用ViewGroup的方法)
@Override
protected View findViewTraversal(@IdRes int id) {
if (id == mID) {
return 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 v;
}
}
}
return null;
}
簡(jiǎn)單的說(shuō)如果當(dāng)前ViewGroup(或者其子類(lèi)的)mID == id 為true撩笆,也就找到了要查找了View,如果不相等則會(huì)去遍歷ViewGroup的子View數(shù)組抒线,如果在子View的找到就返回班巩;如果遍歷完所有的子View都沒(méi)有找到則返回null。這里的遍歷類(lèi)似于樹(shù)的先序遍歷,
我們?cè)诳匆幌略赩iew類(lèi)中的實(shí)現(xiàn)
protected View findViewTraversal(@IdRes int id) {
if (id == mID) {
return this;
}
return null;
}
View類(lèi)似于樹(shù)的葉子節(jié)點(diǎn)抱慌,它沒(méi)有子布局(節(jié)點(diǎn))逊桦,所以他的遍歷很簡(jiǎn)單,就是簡(jiǎn)單比較id是否相等抑进,相等就返回當(dāng)前View强经,不相等則返回null;
簡(jiǎn)單總結(jié)
使用findViewById時(shí),最終會(huì)調(diào)用ViewGroup中的findViewTraversal寺渗,這個(gè)方法會(huì)遍歷所有的子View匿情,形成一個(gè)遞歸查詢(xún),找到最末端(View中)信殊。如果找到就會(huì)返回這個(gè)View并停止查詢(xún)炬称,如果沒(méi)找到就會(huì)返回為null。在確定要查找的那個(gè)View在某個(gè)View中的時(shí)候涡拘,我們調(diào)用那個(gè)View.findViewById()方法玲躯,會(huì)減少查詢(xún)的循環(huán)次數(shù),提高效率鳄乏。