Replacing Custom Views with View Binding
How we used View Binding to replace Custom Views
In our codebase, we use a lot of custom views for reusability — but most of the time, a custom view was overkill. Here’s how we used View Binding to replace some of our custom views.
View Binding 101
If you are not familiar with View Binding yet, here is a great post by Sean McQuillan about it. In short: View Binding is a better alternative over Kotlin Synthetics, findViewById and good old Butterknife. It allows you to access the views in a layout in a type-safe and null-safe way.
For each XML layout, View Binding generates a binding object. For a layout fragment_login.xml
, you’d get a binding object called FragmentLoginBinding
.
Instantiating the binding objects requires a bit of boilerplate to make sure it is scoped to the components’ lifecycle. We use a delegate class as suggested in this post to make the code cleaner and easier to read.
About Our Custom Views
We used many custom views for our reusable components. Like this one:
Custom views are awesome if they are used right, but they bring quite a bit of boilerplate and are harder to maintain then XML layouts. For cases where we don’t do any custom rendering, View Binding made more sense to use as we could cut down on the boilerplate.
Using View Binding for Reusable Components
As View Binding generates a binding object for each layout, the first step for migrating was to create a layout:

Now for our card_user_data.xml
, View Binding generates a CardUserDataBinding.java
which we can use.
Binding the data
First, we need to include the card layout in our fragment’s layout.
View Binding will automatically cast the type of the <include>
to CardUserDataBinding
, so we can use it in a type-safe way. That also means we can reuse those bindings across layouts. Beware that <merge>
isn’t fully supported in View Binding as of April 2020.
With this, the binding logic will have to be rewritten every time though, and if we change something in the layout (like a views’ id or adding another view), we’d have to change it in a lot of places. Luckily, Kotlin has…
Extension Functions!
We can make the binding logic reusable by defining an extension function on the binding. Being a developer who is bad at naming, I call those Binding Extension Functions.
Using our extension in the Fragment looks like this:
Each of those Binding Extension Functions lives in its own file in a binding
package so we can keep a good overview of them.

Binding more complex data structures
A nice benefit is that instead of passing multiple parameters separately, you could also pass a model (e.g. a data class). With this, you don’t have to destructure your model first.
For more complex models, using Kotlin standard functions also can help.
“Wait, isn’t that Data Binding?”
Conceptually, this approach does what Data Binding does: Bind data to UI Framework components. The difference is that the binding logic is defined in top-level Kotlin functions. This can be seen as either good or bad, but expressions in XML can get too complicated and hard to read very fast — a danger that is harder to run into in Kotlin code.
What about Build Speed and Performance? 👀
While View Binding generates classes, the impact on build times is small — in lab testing from Google, the increase was at about 1ms per layout file. Talking to other developers using View Binding, none reported a noticeable impact on build times. One developer said the build time observed using gradle-profiler
increased by 1.831s
with 318 View Binding classes generated, which equals about 5.758ms
per View Binding class. View Binding’s Bytecode is also optimised.
Binding Extension Functions also don’t have a noticeable impact on build speed from my (felt) experience, although I didn’t run any benchmarks yet.
Changing something in only the Binding Extension Functions works very well with Apply Changes, making development a lot easier and faster.
Should I do this?
After coming up with this idea, we asked ourselves if this is a good thing to do.
Comparing against Data Binding, Binding Extension Functions shine, both in readability and build speed. Looking at Custom Views, our code was more concise as we got rid of unneeded noise — we went from 21+ lines of code in our UserCardView
to 7 lines for our binding.
While I don’t have any hard numbers (yet), comparing against recompiling after changes in custom views, I did not notice an increase in build times.
Comparing against Data Binding, the performance is better since no annotation processing is involved.
Finally, the Binding Extension Functions are just as reusable as custom views which makes them a lovely alternative.
Maybe Binding Extension Functions are something for you to try out as well — let me know if you have any feedback!
Thanks to Florina Muntenescu, Volodymyr Buberenko and Sinan KOZAK and Volodymyr Galandzij for reviewing!
