欢迎访问[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. Activity启动过程分析
  2. android UI线程安全问题
  3. Android(安卓)EditText默认不弹出输入法的实现方法
  4. Android(安卓)SharedPreferences 实现原理
  5. 给学android的同学们的一些建议【III】
  6. android 温故知新之fragment中易忽视的onViewStateRestored()
  7. Android中打开新的Activity的三种方法
  8. 浅谈Java中Collections.sort对List排序的两种方法
  9. Python list sort方法的具体使用

随机推荐

  1. android获取图库图片并返回
  2. Android查询SIM卡所有信息
  3. xamarin android edittext点击弹框
  4. 关于Android工程的构建工具-不定时更新
  5. Android拍照、录像、录音代码范例
  6. android 让 webView 中的超链接失效
  7. android Bitmap getByteCount和getRowByt
  8. Android视频播放项目总结之 使用Android
  9. android实现 服务器功能
  10. android的PowerManager和PowerManager.Wa