How to easily cache Kotlin Android synthetics

Simply changing import statements can improve performance.

In Android projects written with Kotlin, you can replace findViewById<ViewType>(R.id.view_id) calls by simply writing view_id. The Kotlin Android Extensions plugin adds this synthetic extension property automatically to Activities, Fragments, Views, and classes with the LayoutContainer interface.

The performance issue

Views don’t cache the extension property. Using view.view_id is equivalent to calling findViewById every time and looking up the view over and over again. This is an easy mistake to make in fragments, where you can get the root view.

MainFragment.kt
import kotlinx.android.synthetic.main.fragment_main.view.*
class MainFragment : Fragment(R.layout.fragment_main) {
fun bindUi() {
view.learn_button.setOnClickListener { ... }
view.connect_button.setOnClickListener { ... }
}
}

The solution

Prefer the extension property on Activities and Fragments as those are cached. You can identify which version you use based on the import statement.

MainFragment.kt
import kotlinx.android.synthetic.main.fragment_main.*
class MainFragment : Fragment(R.layout.fragment_main) {
fun bindUi() {
learn_button.setOnClickListener { ... }
connect_button.setOnClickListener { ... }
}
}

Using LayoutContainer with any class

Classes with the LayoutContainer interface can also cache synthetic extension properties. Just provide a getter for the root view object in containerView, and everything else will work just like Activites and Fragments.

MainFragmentUiHelper.kt
import kotlinx.android.synthetic.main.fragment_main.*
class MainFragmentUiHelper(context: Context) : LayoutContainer {
override val containerView = LayoutInflater.from(context)
.inflate(R.layout.fragment_main, null)
fun bindUi() {
# equivalent to containerView.findViewById(R.id.learn_button)
learn_button.setOnClickListener { ... }
connect_button.setOnClickListener { ... }
}
}