I'm trying to figure out the best way to do Android View Binding in Kotlin. It seems like there are a few of options out there:
findViewById
val button: Button by lazy { findViewById<Button>(R.id.button) }
Butterknife
https://github.com/JakeWharton/butterknife
@BindView(R.id.button) lateinit var button: Button
Kotlin Android Extensions
https://kotlinlang.org/docs/tutorials/android-plugin.html
import kotlinx.android.synthetic.main.activity_main.*
I'm pretty familiar with findViewById and Butterknife in java land, but what are the pros and cons of each view binding approach in Kotlin?
Does Kotlin Android Extensions play well with the RecyclerView + ViewHolder pattern?
Also how does Kotlin Android Extensions handle view binding for nested views via include
?
ex: For an Activity using activity_main.xml
, how would View custom1
be accessed?
activity_main.xml
<...>
<include layout="@layout/custom" android:id="@+id/custom" />
</>
custom.xml
<...>
<View android:id="@+id/custom1" ... />
<View android:id="@+id/custom2" ... />
</>
kotlin-android-extensions
is better for Kotlin
. ButterKnife is also good but kotlin-android-extensions
is a better and smart choice here.
Reason : Kotlin
uses synthetic
properties and those are called on demand using caching function
(Hence slight fast Activity/Fragment loading) while ButterKnife
binds all view at a time on ButterKnife.bind()
(that consumes slight more time). With Kotlin
you don't even need to use annotation for binding the views.
Yes it also plays good with RecyclerView + ViewHolder pattern, you just need to import kotlinx.android.synthetic.main.layout_main.view.*
(if layout_main.xml
is Activity/Fragment layout file name).
You do not need to do any extra effort for layout imported using include
. Just use id of imported views.
Have a look at following official documentation notes:
Kotlin Android Extensions is a plugin for the Kotlin compiler, and it does two things:
- Adds a hidden caching function and a field inside each Kotlin Activity. The method is pretty small so it doesn't increase the size of APK much.
Replaces each synthetic property call with a function call.
How this works is that when invoking a synthetic property, where the receiver is a Kotlin Activity/Fragment class that is in module sources, the caching function is invoked. For instance, given
class MyActivity : Activity()
fun MyActivity.a() {
this.textView.setText(“”)
}
a hidden caching function is generated inside MyActivity, so we can use the caching mechanism.
However in the following case:
fun Activity.b() {
this.textView.setText(“”)
}
We wouldn't know if this function would be invoked on only Activities from our sources or on plain Java Activities also. As such, we don’t use caching there, even if MyActivity instance from the previous example is the receiver.
Link to above documentation page
I hope it helps.