Kotlin Android View Binding: findViewById vs Butterknife vs Kotlin Android Extension

triad picture triad · Sep 29, 2017 · Viewed 12k times · Source

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" ... />
</>

Answer

chandil03 picture chandil03 · Sep 29, 2017

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:

  1. 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.
  2. 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.