Using View Binding With Convenience .

Ditching the Kotlin synthetics and Architecting view binding into the core of an app in a clean manner, thanks to generics and Kotlin delegates.

The Basics.

View binding is the cool new solution for accessing the layout views. A lot of good, in depth material is available about it on the internet, so I won’t go into much basics. However here is a slide from my end to give you a quick refresher on this topic:

The challenge.

View binding is useful, but quite verbose . just to access a textview from xml, we need to create binding instances and access as binding.textViewId. In case of activities and fragments, we also need to make sure that the binding instance is accessed in lifecycle aware manner. Thus we end up writing a lot of repetitive code in every class that we wanna use view binding in. This was the problem that arrived when we thought of converting our app (with many activities, fragments, and other view components) to view binding.

Fortunately there is a solution for that, which comes as a result of combination of Kotlin Delegates , Generics, Inheritence and a coding style that we have been previously following. Let me explain in detail.

The coding style

We don’t use snake case in our xml view ids. instead of tv_user_name, we would use tvUserName . This worked well with synthetic binding and this worked like a charm with view binding. By the end of this article, you will see how we added just 13 characters to convert a particular function from using synthetic binding to view binding

The Generics and Inheritance.

The Generics classes are the best when some code needs to be reused . Wanna store a list of integers ? val a = List<Int>() Requirement changed and we now want to store a list of strings? val a = List<String>() The SDK is filled with generic classes which help reuse same code for different data types. Combined with base classes, they work like a charm

A typical thing about View binding classes is that they are generated based on the name of xml file and 2 View Binding classes generated for different xmls won’t be sharing anything common except a similar overall structure and the fact that both extend ViewBinding interface.

Thus, to reduce the duplication in general usage, we need to come up with a base class that could create and hold the instance of every child class, like:

class BaseVbParentFragment<T:ViewBinding> :Fragment(){
val binding : T = ViewBindingUtil.create(T::class)
}

Sadly the view binding tool does not create any such ViewBindingUtil class that could generate a view binding instance for any class T . Thus , the task of creation will always be done by the child class only. however this does not mean we cannot use a base class for holding the instance of view binding class. Thus we can have something like :

The first file ( BaseFragmentVB ) is a generic base class that every fragment can extend. Its main tasks are :

  1. To enforce child class to create an instance of their ViewBinding class and provide it to base class, which shall manage its lifecycle. This is done via the abstract method attachBinding . We also uses the concepts of effectively final variable by which we are able to achieve 2 targets at once : getting an instance of child class’s View binding and preventing them from direct access to their own binding
  2. To provide the view to the base classes : This is done via the private function getExternallyInflatedView()

3. To provide the access to view binding class instance access to base class, which was done via getBinding() function

The second file is an example of how it is being used in a child class. As I said, add just a few characters , enclose the views in higher order functions and we have a class using synthetic binding converted to view binding !

Create a similar base class for activities and most of your most of the code base can now be moved to View binding with ease 😁 . Just the difference would come in lifecycle functions.

Kotlin Delegates.

The above code was working fine for us, but there was a small flaw in it. The methods that were used for accessing the view binding were still too long and restricting. furthermore there are instances when we need to access a view in onDestroy() or onDestroyView() , like for removing a particular listener from a video player. usually the synthetic binding code works, as we create a nullability check before, like exo_view?.removeListener(..) .Thus there was a need to provide more and convenient access methods.

Furthermore if you think about it, the base class is interacting with lifecycle components, so it should be only focussing on that and the job of creation and destruction of the binding could be delegated to a seperate class. This will further optimise the BaseBinding classes and reduce the chances of error while scaling. Kotlin’s delegation by implementation feature just happen to do that :

Some Explanation:

  1. VbHelpers is a basic interface that provides definition for various functions that could be used for accessing a view binding class instance . It does not have methods for modifying the view binding instance as one of our goals is to not allow children classes from modifying the base binding instance
  2. The VbHelpersImpl is a basic manager class that is responsible for creation and management of a View Binding class instance . It implements VbHelpers interface to support delegation by implementation . It also has some public methods such that the class having an instance of VbHelpersImpl can access those methods but the classes using it as implementation of VbHelpers can’t access those
  3. The BaseFragmentVB is modified accordingly. Now it only manages the lifecycle of binding instances (indirectly) and provides the inflated binded view to the parent classes
  4. The child classes can now use the new higher order functions withBinding{this:it:ChildClassBinding -> ...} , usingBinding{it:ChildClassBinding -> ...} and getBinding() to access it even more conveniently .

End Notes

Well this was it folks. View binding is quite verbose on its own, but offers some good features . And since Jetbrains has announced the deprecation of Kotlin-Android-Extensions, View binding seems to be the only valid alternative.

If you found this article as useful, then do give a 👏 . I will be happy to answer any doubts in comments. Corrections are welcome . Connect with me on my social media handles if you like food/tech :

curiously fiddling around with tech | https://root-ansh.github.io/curioustools/

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store