[android]深入理解findViewById原理

时间:2021-08-10 22:06:55

用的太多了,但是不知道原理。Xutils里面舍弃了findViewById改用注解,当时也很不理解。一步步了解后,发现,相比注解的方式加载控件,findViewById的效率是很低的。注解+反射加载实例的过程看上去效率更高。


从activity的onCreate()里开始:


[android]深入理解findViewById原理

点进去看源码进入Activity.class类里的方法:

Activity.class

[android]深入理解findViewById原理

发现这个返回的是getWindow()的findViewById方法,这个getWindow()是什么?

Activity.class

[android]深入理解findViewById原理

返回的是一个Window对象,Window是个抽象类,包含的抽象方法可以管理Activity的UI组件,先这么理解,这次主要理解findViewById的原理。


既然Activity的findViewById,是调用getWindow()(即Window对象)的findViewById方法,进入Window查找它的findViewById。


Window.class

[android]深入理解findViewById原理

返回的是getDecorView()的findViewById,前面说Window是个抽象类,不能具体实现管理ActivityUI组件的方法,那么这个getDecorView()就是返回的是一个具体的View对象,来管理Activity的UI组件。[android]深入理解findViewById原理

这个getDecorView是个方法,返回的View可以用来管理UI视图。

[android]深入理解findViewById原理

然后Activity的findViewById方法,又通过getDecorView()(返回View)一步一步传入到View的findViewById了。下面是View类。



View.class

[android]深入理解findViewById原理

逻辑很简单了,直接调用findViewTraversal(),用mID跟传入的id对比,如果存在就返回当前view,不存在就返回null。findViewTraversal从字面上理解,这个方法的意思是反复寻找view的ID。

[android]深入理解findViewById原理

到这里我有点没有头绪了,凭感觉,查找mID应该是不断+1比较,如果是ViewGroup,里面还有View的话,还应该是一个递归的过程,从这里看不出来。所以我看是找mID是如何设置的。

这是一个set方法,给子view控件添加ID,用来标识view。这个ID可以在R文件里看到。

[android]深入理解findViewById原理

先把id给了mID,如果mID为空(就是没有加ID呢),而且不是作为标签(不太懂),那么就给他加一个ID,动态生成控件的ID。

[android]深入理解findViewById原理


一个固定地址开始,一个一个找ID,设置的ID值似乎连续的。然后在后面的查找中,找递归,找循环。。没有找到类似的代码。

看上去,要知道mID才能知道答案。但是这样分析下去得不到结果。

原因:

请看LinearLayout,RelativeLayout等等layout的继承结构:

[android]深入理解findViewById原理


在ViewGroup中,已经对View的findViewTraversal()方法进行重写了!

点进去找很快找到答案。

这个是重写的方法:可以非常清楚的看到,findViewById的原理,是从头开始找,遇到有子控件的,就递归接着找。先不考虑具体细节,到这里,开始的猜想得到了证实。其中v.findViewById又调用View中的方法,而View的findViewById调用的findViewTraversal()。这样实现了一个递归。


尊重作者注明出处:http://blog.csdn.net/bless2015/article/details/46618639


[android]深入理解findViewById原理


我在找findViewById的过程中,由于开始忽略子类ViewGroup对View方法的重写,导致在View.class万行代码中陷入死循环,找不到想看到的方法。但是还是找到一些有趣的东西,有时间再整理下来。