Android View Binding Without Boilerplate — Part 1
View Binding is a great feature inspired by Butter Knife that replaces findViewById
and Kotlin synthetics. For each XML layout a corresponding Binding class will be generated that bridges the gap between your Kotlin and XML.
The problem is there’s a little extra boilerplate you have to put in every fragment in order to properly use it according to the android documentation.
private var _binding: ProfileBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = ProfileBinding.inflate(inflater, container, false)
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
First of all we need to declare two bindings, a _binding
and binding
. This may look very strange to those unfamiliar with it, but this is a Kotlin pattern called backing properties. The purpose of it here is to have a property that is in a sense lateinit but also nullable. And the other annoying thing is having to null binding in onDestroyView to follow safe cleanup practices.
With delegates we can avoid the need for backing properties. And with lifecycle observers the days of having to write boilerplate to cleanup resources at steps of the lifecycle should be over. And that’s what I’m going to show you how to do, see below.
private var binding: ProfileBinding by nullOnDestroy()override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = ProfileBinding.inflate(inflater, container, false)
return binding.root
}
That’s it! Only one binding and we don’t even need an onDestroyView anymore. Here is the code.
Note that this isn’t coupled to View Binding in any way. If there’s anything at all that you need to null on destroy, then you can use this delegate for it.
Fragments (due to bad design) have two lifecycles: lifecycle
and viewLifecycle
. lifecycle
ranges from onCreate
to onDestroy
whereas viewLifecycle
ranges from onCreateView
to onDestroyView
. viewLifecycle
is above and beyond the more important lifecycle and the one you want to pay attention to whereas you can largely ignore the other one.
The only slightly tricky thing going on here is in the init block. We’re observing viewLifecycleOwnerLiveData
and then within the observe observing it.lifecycle
which in this case is the viewLifecycle
. A fragment’s viewLifecycle
is null and not available until onCreateView
happens, but luckily viewLifecycleOwnerLiveData
exists and will tell us when viewLifecycle
becomes available. Note there is no need to remove the observer because a fragment’s viewLifecycle
is correspondingly nulled and no longer available after onDestroyView
. In fact trying to access viewLifecycle
outside the view lifecycle results in an IllegalStateException.
Checkout part 2 for more.