Android View Binding — less boilerplate, more delegate

Vadim Sukharev
3 min readJun 12, 2021
Image taken from https://www.growmyteam.com.au/blog/is-your-inability-to-delegate-rotting-your-culture

After Google introduced the view binding feature, you’ve been able to access views following type- and null safety. But on the other hand, implementing it as is, you’re forced to write boilerplate code. In this article, you’ll get rid of the boilerplate, having a view binding property to be nullable and sync it with both activity and fragment lifecycle

If you’re eager to get the problem done

implementation 'io.github.vsukharew:viewbindingdelegation:1.0.1'

Otherwise you can go through all the steps of implementation and get the same result

Creating a base class for delegation

This class stores the binding property itself and the lifecycle object which belongs to activity or fragment. LifecycleObserver implementation allows to release these references and unsubscribe from the android component when it is destroyed.

Activity

Having defined the base properties and their release logic, you’re able to create the Kotlin delegated property that will initialize our activity’s binding property

The ActivityViewBindingProperty implements the ReadOnlyProperty interface, as Kotlin documentation requires. This interface is typed with two parameters:

  • AppCompatActivity — which defines the type of object that owns the delegated property
  • T — type of the delegated property itself (remind that T inherits the ViewBinding interface)

Its constructor takes the lambda that inflates the view binding object by means of LayoutInflater.

In the implementation, you either return the binding property, if it has been already initialized or run the block that subscribes to the activity lifecycle and runs the lambda that creates the binding property. This block also captures the lifecycle and binding objects to release them when activity get destroyed.

Fragment

Let’s implement such a delegate for the fragment properties:

This case is a little more complex because in fragment, you have to pass the appropriate parameters into the LayoutInfater’s inflate method:

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)

But you can’t access particularly the root outside of a fragment’s onCreateView. So you need to create the ViewBinding object based on the fragment’s view. That’s why it is the parameter that’s passed into the constructor. Later you’ll see why it is called viewBinder

The rest of the implementation looks very similar to activity’s one except it is typed with the Fragment and the subscription is run on viewLifecycleOwner’s lifecycle. It is important because this way we observe the fragment’s UI lifecycle instead of object’s overall one.

You can also add the wrapper functions for more convenient calls:

Usage

The simplest case is the usage in activity:

In fragment, it’s better to create a base class where you define the binding and layout properties and create layout in the onCreateView method:

And inside derived classes override these properties and access views:

Pay attention, you inflate layout as usually do and then create the ViewBinding object and bind the inflated view to it. That’s why that lambda is called viewBinder.

Since dialogs are also inherited from fragments you can delegate the binding property initialization the same way:

Conclusion

This way with the help of Kotlin delegated properties and Android LifecycleObserver you can stop caring about ViewBinding nullability and possible memory leaks.

If you want to try the sample project and make sure everything works correctly, check the GitHub repo.

--

--