Kotlinx不使用findViewById的原理

原生页面的开发有一个让人头疼的地方:页面中控件非常多,堆砌了大量的控件声明与控件绑定代码。很明显,这属于我们想要避免的重复劳动。

而正好,Kotlin给我们提供了一个解决方法,kotlin-android-extensions,在app/build.gradle中加入下面两句即可:

apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

引入了kotlin-android-extensions后,控件的使用就变得非常简洁了,在代码中直接使用xml中定义的控件名即可。

接下来要思考的问题是,为什么可以直接使用控件名去操作控件,而不用再显式地使用findViewById。

我们可以反编译Kotlin代码,查看其对应的Java代码来一探究竟:

首先在Android Studio中,点击顶部的Tools -> Kotlin,然后选择Show Kotlin Bytecode,这样在右侧就打开了Koltin代码对应的字节码,接下来,点击字节码界面左上方的Decompile,就得到了Kotlin代码对应的Java代码。

可以看到,et_account控件操作对应的代码是:

Kotlinx不使用findViewById的原理

我们再看一下这个findCachedViewById方法:

Kotlinx不使用findViewById的原理

可以看到,在这个方法里有一个名为findViewCache的HashMap,用来缓存每次找到的View,避免每次对View进行操作时都重新调用findViewById方法,是的,在这里,仍然是通过findViewById去获取控件的,而且每个控件的第一次使用都会调用findViewById方法,后续的使用可以在findViewCache中去获取。

另外一个需要注意的地方是,在Fragment中使用时,需要注意不能在onCreateView中直接使用控件,否则会crash,应该在onViewCreated中去使用,具体的原因如下:

Kotlinx不使用findViewById的原理

可以看到,fragment对应的findCachedViewById方法与activity对应的有所不同,它需要先调用getView方法,然后再通过getView返回的值去findViewById,那么getView方法的返回值其实是mView,也就是fragment的根view:

Kotlinx不使用findViewById的原理

继续看一下mView的赋值时机:

Kotlinx不使用findViewById的原理

可以看到mView其实就是onCreateView的返回值,所以我们不能在onCreateView中去直接操作控件。

上一篇:Java导入excel并保存到数据库


下一篇:Android ViewFlipper的使用(上下滚动)