Kotlin 不再使用 findViewById 的原理探析

使用过 Kotlin 的都知道, Kotlin 一个非常棒的特性是:可以在 .kt 文件中直接使用控件的 ID 对控件进行操作。而 Java 代码中,需要像先式声明控件,再使用 findViewById() 来找到控件,然后才能操作该控件。该特性称为Static Layout Import,即静态布局引入。

举个栗子,假设某个 activity 的 xml 文件: activity_main.xml 中有个 TextView 控件,其 ID 定为 tv_name ,在对应的 .kt 文件中将布局如下引入进来后:
这里写图片描述
就可以直接使用其ID tv_name来操作这个 TextView 控件了:
Kotlin 不再使用 findViewById 的原理探析_第1张图片

可以看到,利用我们在 xml 中 定义的 ID tv_name,就可以直接使用该 TextView 的 text、textSize 等属性或方法,甚至比著名的第三方开源库 ButterKnife还要方便简洁。妥妥的黑科技有木有,大道至简~~
ps:text / textSize 等属性其实是 Kotlin 扩展属性,通过反编译查看底层的 Java 代码,可以发现其实还是使用其对应的 setter 方法,即setText()/setTextSize()。

那么问题来了,Kotlin 可以直接使用控件 ID 来操作控件,是如何做到的呢?

我们先将 Kotlin 代码转换为对应 Java 代码。

在 Android Studio 中,点击最顶部的 Tools -> Kotlin,然后选择 Show Kotlin Bytecode,可以在右侧面板中看到对应的字节码,然后点击 Decompile ,就可以查看 Kotlin 代码对应的 Java 代码:
Kotlin 不再使用 findViewById 的原理探析_第2张图片

可以发现,tv_name 部分的代码对应的 Java代码如下:
Kotlin 不再使用 findViewById 的原理探析_第3张图片
通过反编译后的代码,可以看到这个黑科技的原理就一目了然了 。Kotlin 会自动生成类似 findViewById() 的方法:findCachedViewById(),在这个方法里面创建一个 HashMap 来缓存每次查找到的 View,避免每次调用 View 的属性或方法时都会重新调用findCachedViewById()进行查找。具体查找流程是这样的:在findCachedViewById()中,会先通过缓存 HashMap 的 get 方法来获取控件, get() 中传入的 key 即控件 ID,由于第一次 get 的值为 null ,因此会调用findViewById() ,并把控件 ID作为 key 和 找到的控件 View 作为 value ,put 进 HashMap 缓存中,这样,第二次再使用该控件 ID 的时候,就直接可以从 HashMap 中获取到了。很简单吧。

以上就是在 activity 中里面直接使用控件 ID 的原理分析。

但是在 fragment 里面使用就需要注意了,不要在onCreateView方法里用 view 的 ID,而是在 onViewCreated以后使用,否则可能会由于找不到控件而出现空指针异常的问题。正确的姿势是这样的:
Kotlin 不再使用 findViewById 的原理探析_第4张图片

同样,将上述 Kotlin 代码转化为对应的 Java 代码:
Kotlin 不再使用 findViewById 的原理探析_第5张图片
可以看到, fragment 里面跟前面 activity 的基本原理类似,同样也是在findCachedViewById()中创建 HashMap 缓存 。区别在于: fragment 里面是通过getView()findViewById()的,如果是在onCreateView方法里使用控件 ID,这个时候getView()会返回 null,即 var10000null,这样findCachedViewById()就返回空了。

因此,千万要注意, fragment 里面不要在onCreateView方法里用 view 的 ID。

通过以上探究,Kotlin 中可以不再使用 findViewById、而是直接使用控件 ID 来操作控件 的原理就分析完啦。

总结:

  • Kotlin 可以直接使用 id 来操作控件的原因是其底层做了类似 findViewById 的转换来找到对应的控件,并且找到后会缓存起来;

  • fragment 中不要在onCreateView方法里用 view 的 ID,而是应该在onViewCreated以后使用。

你可能感兴趣的:(Android)