View Binding is an upcoming feature in Android, available in Android Studio 3.6 Canary 11+ which allows you to more easily interact with Views. It’s quick and easy to enable, and allows for type-safe view access. We’re likely all going to be using it in Fragments. Let’s explore how we can use it, in a safe and easy way!

View Binding in Fragments

Let’s take a look at the example from the View Binding Documentation. First we define some layout file:

result_profile.xml

<LinearLayout ... >

<TextView android:id="@+id/name" />

<ImageView android:cropToPadding="true" />

<Button android:id="@+id/button"

android:background="@drawable/rounded_button" />

</LinearLayout>

This then generates a “binding” class, ResultProfileBinding . This class contains two fields, name and button , which refer to the views in our layout file. Nice!

Using this binding in a Fragment takes one more step — inflating it in onCreateView , and returning the root view. For example:

override fun onCreateView(

inflater: LayoutInflater,

container: ViewGroup?,

savedInstanceState: Bundle?

): View? {

_binding = ResultProfileBinding.inflate(inflater, container, false)

val view = binding.root

return view

}

Here we’re storing our binding class in a property so that we can access it later. As it turns out, due to the lifecycle of Fragment Views, this isn’t all we have to do.

Keeping Track of Lifecycle

When our view is destroyed we need to remember to clear our property, otherwise we’ll end up with a memory leak at best, and crashes at worst! The documentation recommends you do the following in your Fragments:

private var _binding: ResultProfileBinding? = null // This property is only valid between onCreateView and

// onDestroyView.

private val binding get() = _binding!! override fun onDestroyView() {

_binding = null

}

This method works, but you can see how adding this to several different Fragment classes could get repetitive, and start to feel like boilerplate. Luckily for us, we can shorten this considerably in our Kotlin Fragments!

private var binding: ResultProfileBinding by viewLifecycle() override fun onCreateView(

inflater: LayoutInflater,

container: ViewGroup?,

savedInstanceState: Bundle?

): View? {

binding = ResultProfileBinding.inflate(inflater, container, false)

val view = binding.root

return view

}

We now no longer have to override onDestroyView , and we've decreased the number of properties we have to write! But wait.. viewLifecycle() isn't in AndroidX? How did we do that? By writing our own Property Delegate!

Let’s look at the full definition of viewLifecycle() and break it down:

fun <T> Fragment.viewLifecycle(): ReadWriteProperty<Fragment, T> =

object: ReadWriteProperty<Fragment, T>, LifecycleObserver {



// A backing property to hold our value

private var binding: T? = null



init {

// Observe the View Lifecycle of the Fragment

// * See Gist for full code *

this@viewLifecycle

.viewLifecycleOwnerLiveData

.observeLifecycles()

}



@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)

fun onDestroy() {

// Clear out backing property just before onDestroyView

binding = null

}



override fun getValue(

thisRef: Fragment,

property: KProperty<*>

): T {

// Return the backing property if it's set

return this.binding!!

}

override fun setValue(

thisRef: Fragment,

property: KProperty<*>,

value: T

) {

// Set the backing property

this.binding = value

}

}

Wow, there’s a lot going on there. Let’s break it down.

viewLifecycle() is an extension function of Fragment , meaning we can use Fragment -related properties.

is an extension function of , meaning we can use -related properties. viewLifecycle() returns a ReadWriteProperty<Fragment, T> , an implementation of a property of a Fragment, which is of the generic type T .

returns a , an implementation of a property of a Fragment, which is of the generic type . We construct an anonymous class which implements ReadWriteProperty and LifecycleObserver , allowing us to listen to Lifecycle Events.

and , allowing us to listen to Lifecycle Events. In the init block, we observe the Fragments viewLifecycleOwner . A Fragment’s View can be created and destroyed many times, so it may have more than one Lifecycle. AndroidX Fragment makes it easy for us, by including viewLifecycleOwnerLiveData , which emits the new Lifecycle Owner when the View is recreated.

block, we observe the Fragments . A Fragment’s View can be created and destroyed many times, so it may have more than one Lifecycle. AndroidX Fragment makes it easy for us, by including , which emits the new Lifecycle Owner when the View is recreated. Finally, when the View’s Lifecycle Owner changes, we observe the new Lifecycle. On the ON_DESTROY event , sent when onDestroyView is about to be called, we null out our backing property.

This gives us the same behaviour as in the View Binding Documentation, but with much less code to cart around in our Fragments! You can find a full, more flexible example in this Gist, which you can drop in to your project and start using!