欢迎访问[Android日记][1],如有转载请注明Android日记 http://androiddiary.site
2017.1.10 周二 晴 临沂


写日记

从findViewById()说

还记得三年之前学习android就开始使用findViewById,但是用了这么久还没有具体分析过他的实现,今天终于有机会仔细看看。

  1. 在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);}
  1. getWindow:
public Window getWindow() {    return mWindow;  }

mWindow 是 private Window mWindow; 是一个Window类型的变量

  1. 再看Window类中的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);}
  1. 发现getDecorView()是Window中的一个抽象方法。而Window唯一的子类是PhoneWindow.

  2. 在PhoneWindow找到getDecorView()方法

@Overridepublic final View getDecorView() {    if (mDecor == null || mForceDecorInstall) {        installDecor();    }    return mDecor;}

而mDecor是Phone的一个内部类DecorView

private final class DecorView extends FrameLayout implements RootViewSurfaceTaker 

它继承了FrameLayout ,而FrameLayout 是ViewGroup的子类

  1. 最终我们在View类中找到了
/** * 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类的findViewById中调用的方法findViewTraversal只在ViewGroup里面被重写(Override)了。
我们先看一下ViewGroup中的实现(因为mDecor是ViewGroup的子类会调用ViewGroup的方法)

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

简单的说如果当前ViewGroup(或者其子类的)mID == id 为true,也就找到了要查找了View,如果不相等则会去遍历ViewGroup的子View数组,如果在子View的找到就返回;如果遍历完所有的子View都没有找到则返回null。这里的遍历类似于树的先序遍历,
我们在看一下在View类中的实现

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

View类似于树的叶子节点,它没有子布局(节点),所以他的遍历很简单,就是简单比较id是否相等,相等就返回当前View,不相等则返回null;

简单总结

使用findViewById时,最终会调用ViewGroup中的findViewTraversal,这个方法会遍历所有的子View,形成一个递归查询,找到最末端(View中)。如果找到就会返回这个View并停止查询,如果没找到就会返回为null。在确定要查找的那个View在某个View中的时候,我们调用那个View.findViewById()方法,会减少查询的循环次数,提高效率。

更多相关文章

  1. Android SDK 安装中组件的离线安装方法 (share)
  2. Android中打开新的Activity的三种方法
  3. Android EditText默认不弹出输入法的实现方法
  4. activity中onSaveInstanceState方法调用时机详解
  5. Android 利用getIdentifier()方法获取资源ID
  6. Android cursor query方法详解
  7. [置顶] Android系统安全之旅 第1章 编译Android程序的方法

随机推荐

  1. 最新基于adt-bundle-windows-x86的androi
  2. android ListView的滑动效率问题
  3. [置顶] 学习链接
  4. android 开发问题----avd按钮无法按
  5. android系统自带的intent集锦
  6. android开发教程(八)——环境搭建之android
  7. varnish 配置使用 Chrome,iphone,android
  8. 编译用于Android的busybox---步骤,问题和
  9. Vue和ios、android交互通信
  10. Android(安卓)基于paho的mqtt service的