---
title: "Let your delegates auto-nullify references☠️ | Shreyas Patil's Blog"
description: "Learn how to use Kotlin property delegates to automatically nullify references in Android, preventing memory leaks in Fragments and Activities."
image: "https://blog.shreyaspatil.dev/_astro/cover-let-your-delegates-auto-nullify-references.DzBtReak.png"
---

# Let your delegates auto-nullify references☠️

Hello Android developers 👋, In this article, we’ll explore Kotlin’s Delegated property feature to solve a common problem in Android which will help us to reduce memory leaks.

*Memory management* is an important thing to take into consideration while developing a good and performant application. While developing any application, a **memory leak** is a common problem while developing an application if we didn’t handle resources properly as per the *lifecycle* events.

Let me give you examples. Imagine if you have a **Fragment** and it has references to some properties. We need to clear the references to these fields by assigning `null` in `onDestroyView()` lifecycle method so that Fragment won’t hold references to them.

---

## 🎬 Example 1

You may have seen this snippet of code on [official Android’s docs for ViewBinding](https://developer.android.com/topic/libraries/view-binding#fragments) 👇:

```
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)
    val view = binding.root
    return view
}

override fun onDestroyView() {
    super.onDestroyView()
    _binding = null
}
```

Here, you can see that we need to create two fields `_binding` which is a *nullable* backing field for *non-null* field `binding`. What’s the reason for this? Read this 👇:

> Note: As this is mentioned in the official docs. Fragments outlive their views. Make sure you clean up any references to the binding class instance in the fragment’s `onDestroyView()` method.

In this example, we need to declare these things twice. If we forgot to clear reference in `onDestroyView()` then it might lead to issues. We’ll see how to solve this after some time. Till then let’s take a look at another example.

---

## 🎬 Example 2

When you have worked with *RecyclerView,* sometime you might have experienced a memory leak issue due to *RecyclerView.Adapter* even in configuration changes like a rotating screen. So for such cases, again we need to clean adapter reference in `onDestroyView()` lifecycle method as following 👇:

```
private val mAdapter = MyListAdapter() // 1️⃣
// OR private var mAdapter: MyListAdapter? = null 2️⃣

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    // OR Initialize MyListAdapter everytime when View is created 2️⃣
    // mAdapter = MyListAdapter(...)

    binding.recyclerView.adapter = mAdapter
}

override fun onDestroyView() {
    super.onDestroyView()
    binding.recyclerView.adapter = null  // 1️⃣
    // OR mAdapter = null 2️⃣
}
```

Here you can see that we finally setting *RecyclerView’s* *Adapter* as `null`. Alternatively, as mentioned in **OR** (2️⃣) comments, we can also declare `mAdapter` as nullable. But if we do so then we’ll need to use `?` with adapter instance every time we try to access it 😫.

Here again, if we forget to set adapter as `null` in `onDestroyView()` then it might be a problem if there’s any process that tries to access the adapter.

In both examples, we used backing fields for references like `_ref` for every `ref` and **nullified** it in `onDestroyView()`. So how to avoid this *repetition*, make it *more readable* or *reduce boilerplate* for every Fragment/Activity or Android’s component?

---

## 💡 Solution

The [Jetpack library for Lifecycle](https://developer.android.com/topic/libraries/architecture/lifecycle) is a very powerful library by which we can develop Android *lifecycle-aware* components which allow us to observe the lifecycle of components and thus we can handle things accordingly. Also, Kotlin has a variety of features and the [Delegated property](https://kotlinlang.org/docs/delegated-properties.html) is one of the great features. So let’s see it in action.

I read the source code of [AutoClearedValue](https://github.com/android/architecture-components-samples/blob/08416a0aced0e4946e0765751a3b20f9a6222708/GithubBrowserSample/app/src/main/java/com/android/example/github/util/AutoClearedValue.kt#L31) from official samples and [Gabor Varadi](https://medium.com/u/7a8d96da8cb6?source=post_page-----3ad6d8875497--------------------------------)’s [article](https://medium.com/@Zhuinden/an-update-to-the-fragmentviewbindingdelegate-the-bug-weve-inherited-from-autoclearedvalue-7fc0a89fcae1) where he mentioned a bug in this implementation. So this solution is inspired by the learnings of these two references.

First of all, add these Jetpack Lifecycle Component libraries:

```
implementation 'androidx.lifecycle:lifecycle-common-java8:2.3.0'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.0'
```

Create a class `AutoCleanedValue.kt` where we’ll wrap our logic for auto-nullifying references 👇:

```
class AutoCleanedValue<T : Any>(
    fragment: Fragment,
    private val initializer: (() -> T)?
) : ReadWriteProperty<Fragment, T> {

    private var _value: T? = null

    init {
        fragment.lifecycle.addObserver(object : DefaultLifecycleObserver {
            val viewLifecycleOwnerObserver = Observer<LifecycleOwner?> { viewLifecycleOwner ->

                viewLifecycleOwner?.lifecycle?.addObserver(object : DefaultLifecycleObserver {
                    override fun onDestroy(owner: LifecycleOwner) {
                        _value = null
                    }
                })
            }

            override fun onCreate(owner: LifecycleOwner) {
                fragment.viewLifecycleOwnerLiveData.observeForever(viewLifecycleOwnerObserver)
            }

            override fun onDestroy(owner: LifecycleOwner) {
                fragment.viewLifecycleOwnerLiveData.removeObserver(viewLifecycleOwnerObserver)
            }
        })
    }

    override fun getValue(thisRef: Fragment, property: KProperty<*>): T {
        val value = _value

        if (value != null) {
            return value
        }

        if (thisRef.viewLifecycleOwner.lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) {
            return initializer?.invoke().also { _value = it }
                ?: throw IllegalStateException("The value has not yet been set or no default initializer provided")
        } else {
            throw IllegalStateException("Fragment might have been destroyed or not initialized yet")
        }
    }

    override fun setValue(thisRef: Fragment, property: KProperty<*>, value: T) {
        _value = value
    }
}
```

Let’s understand it:

- `AutoCleanedValue` is implementing a `ReadWriteProperty` which is a base interface from the standard library that can be used for implementing property delegates of read-write properties.

- It has two parameters in the constructor i.e. `fragment` (since we are making it for Fragment as of now) and `initializer` lambda (Optional) which provides the initial value which might be helpful for immutable types.

- There’s a field `_value` which will act as a backing field for references.

- On initialization, we are observing the View lifecycle of a fragment and nullifying it when the view lifecycle is destroyed.

- In short, anybody can’t access the reference once Fragment’s `onDestoryView()` lifecycle method is called.

- If the value is retrieved and if the current value is `null` due to Fragment’s lifecycle then its value will be re-initialized with the help of `initializer` (if it’s provided).

Okay! This is good. Now to make it easy to access from **Fragments**, let’s make an extension function:

```
fun <T : Any> Fragment.autoCleaned(initializer: (() -> T)? = null): AutoCleanedValue<T> {
    return AutoCleanedValue(this, initializer)
}
```

Cool! How we are going to use it? Looks like everything is settled. Let’s see in action how our Fragment will look like after using this delegate? Let’s summarize both the examples we saw in this article in a single snippet 👇:

```
class LeakFragment : Fragment() {

    private val mAdapter: MyListAdapter by autoCleaned { MyListAdapter() }
    private var binding: ProfileBinding by autoCleaned()

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = ProfileBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding.recyclerView.adapter = mAdapter
    }
}
```

That’s it. Looking cool 😍, isn’t it?

### What we achieved?

- We don’t need to have an extra nullable backing field means we don’t need to have two fields for the same reference which will reduce the repetition of fields.

- No need to nullify it manually in `onDestroyView()` since the delegate will take care of it and thus we now can reuse this for every Fragment in a project.

- Thus it’s now more readable with a reduced boilerplate 😎.

Now, this was just for Fragment. If we need we can extend it up to Activity, Service, etc.

I hope you liked this article. Share this if you find it helpful so that it can help someone who needs it. *Sharing is caring!*

Thank you. Have fun! 😄

---

## 📚 References

- [AutoClearedValue source code](https://github.com/android/architecture-components-samples/blob/8f536f2b7012c3c4d7bf80fec0de62893d53edbc/GithubBrowserSample/app/src/main/java/com/android/example/github/util/AutoClearedValue.kt)

- [An update to the FragmentViewBindingDelegate: the bug we’ve inherited from AutoClearedValue](https://itnext.io/an-update-to-the-fragmentviewbindingdelegate-the-bug-weve-inherited-from-autoclearedvalue-7fc0a89fcae1)

```json
{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": "Let your delegates auto-nullify references☠️ | Shreyas Patil's Blog",
  "image": "https://blog.shreyaspatil.dev/_astro/cover-let-your-delegates-auto-nullify-references.DzBtReak.png",
  "datePublished": "2021-03-12T13:39:24.000Z",
  "author": [
    {
      "@type": "Person",
      "name": "Shreyas Patil",
      "url": "https://shreyaspatil.dev/"
    }
  ],
  "keywords": "android-app-development, android, mobile-development, kotlin, kotlin-beginner"
}

{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "name": "Home",
      "item": "https://blog.shreyaspatil.dev/"
    },
    {
      "@type": "ListItem",
      "position": 2,
      "name": "Posts",
      "item": "https://blog.shreyaspatil.dev//posts/"
    },
    {
      "@type": "ListItem",
      "position": 3,
      "name": "Let your delegates auto-nullify references☠️"
    }
  ]
}
```
