Trap in Kotlin Android Extensions
Recently, Google has announced adding Kotlin as one of the official programming languages for Android development. Our team has reviewed its strength and see how it can benefit our daily programming tasks.
One of the most interesting uses is Kotlin Android Extension (https://kotlinlang.org/docs/tutorials/android-plugin.html). This plugin allows developers to remove tedious findViewById()
in the activity. In the past, we used butterknife to handle this problem. However, with this plugin, we can write code like this
comparing to the Java syntax:
Then, we tried to use this in our lovely RecyclerView
too since we saw this attractive statement in the documentation
If we want to call the synthetic properties on
View
(useful in adapter classes), we should also importkotlinx.android.synthetic.main.activity_main.view.*
.
with the list_item_main
layout
Look! We have no more findViewById()
anymore.
How it works?
We are curious about how Kotlin does the trick, so we tried to find out. There are some tools in Android Studio which help us decompile the code. First, the Kotlin Bytecode was extracted by clicking Tools > Kotlin > Show Kotlin Bytecode
. Then we decompiled it into Java by pressing the decompile
button.
The interesting part is here:
There is a function findCachedViewById()
which is used to replace our traditional findViewById()
. The cache is used for performance if we use the view later again. It seems to us that the plugin works properly. FYI, there is a function clearFindViewByIdCache()
but we can’t find any place calling it.
Here comes the main dish — the RecyclerView.Adapter
.
As we look deeply into the onBindViewHolder()
method, the code becomes findViewById()
when we are getting the TextView
. It is obviously violating the ViewHolder pattern. The code might call findViewById()
frequently during the scrolling of RecyclerView
, which can slow down the performance. The correct way to write the ViewHolder is:
and in onBindViewHolder()
In that case, the textView
is already cached when constructing the ViewHolder
object. Thus, no more findViewById()
is needed in onBindViewHolder()
.
Conclusion
It is true that Kotlin and the plugins provide lots of syntactic sugar for us as an Android developer. However, sometimes it may hurt you if you don’t pay attention to how it works. In this case, although findViewById()
is no longer appears in the code, improper use of the plugin may impact the performance. In addition, it makes the code hard to find the problem as the plugin makes the view finding function look like getting field from an Object only!