概述
使用过 Kotlin 的都知道, Kotlin 一个非常棒的特性是:可以在 .kt 文件中直接使用控件的 ID 对控件进行操作。而 Java 代码中,需要像先式声明控件,再使用 findViewById()
来找到控件,然后才能操作该控件。该特性称为Static Layout Import
,即静态布局引入。
举个栗子,假设某个 activity 的 xml 文件: activity_main.xml
中有个 TextView 控件,其 ID 定为 tv_name
,在对应的 .kt 文件中将布局如下引入进来后:
就可以直接使用其ID tv_name
来操作这个 TextView 控件了:
可以看到,利用我们在 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 代码:
可以发现,tv_name
部分的代码对应的 Java代码如下:
通过反编译后的代码,可以看到这个黑科技的原理就一目了然了 。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 代码转化为对应的 Java 代码:
可以看到, fragment 里面跟前面 activity 的基本原理类似,同样也是在findCachedViewById()
中创建 HashMap 缓存 。区别在于: fragment 里面是通过getView()
来 findViewById()
的,如果是在onCreateView
方法里使用控件 ID,这个时候getView()
会返回 null
,即 var10000
为null
,这样findCachedViewById()
就返回空了。
因此,千万要注意, fragment 里面不要在onCreateView
方法里用 view 的 ID。
通过以上探究,Kotlin 中可以不再使用 findViewById、而是直接使用控件 ID 来操作控件 的原理就分析完啦。
总结:
-
Kotlin 可以直接使用 id 来操作控件的原因是其底层做了类似 findViewById 的转换来找到对应的控件,并且找到后会缓存起来;
-
fragment 中不要在
onCreateView
方法里用 view 的 ID,而是应该在onViewCreated
以后使用。
最后
以上就是灵巧酒窝为你收集整理的Kotlin 不再使用 findViewById 的原理探析的全部内容,希望文章能够帮你解决Kotlin 不再使用 findViewById 的原理探析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复