Red lockers and pipes on yellow wall

Photo by Juliana Kozoski on Unsplash

In Android development, forgetting to remove listeners can often lead to memory leaks. Anonymous classes or lambdas holding a reference to a Fragment long after its View is destroyed can silently block precious amounts of memory from being reclaimed. However, cleaning up after ourselves manually every single time is not only cumbersome but error-prone too.

A modern solution to the problem could be the creation of lifecycle-aware components. In this article, I’ll show you an example of my proposed implementation using ViewPager2’s onPageSelected callback, but first, let us quickly walk through the old way of dealing with this issue.

The old way

We start by declaring a listener. Depending on the use-case it can be nullable or lateinit var if it works with anything non-global, or a private property in the Fragment:

We can then register it in a lifecycle event before the screen appears and remove it in the corresponding lifecycle event after the screen disappears:

The plan is to get rid of these callbacks and move the registering and unregistering parts closer to each other, making sure that calling the first one will automatically result in calling the second one when needed.

The new way, aka Lifecycle to the rescue!

The easy way of simplifying and improving the above implementation would be to let Lifecycle deal with the dirty work of adding and removing the listener, with our code looking something like this:

binding.pager.onPageSelected(viewLifecycleOwner) { position ->
// Do stuff
}

To get there first, we create the following extension function for ViewPager2:

fun ViewPager2.onPageSelected(
    lifecycleOwner: LifecycleOwner,
    listener: (position: Int) -> Unit
)

By marking it inline, we make sure to avoid the runtime penalty of unnecessary memory allocation.

We can implement the callback interface to hook in our lambda:

…and make the component lifecycle-aware so that it will handle registering and unregistering itself.

There, that’s it. It does the job, but there’s still some room for improvement. If you’d rather use lambdas for the lifecycle callbacks to improve readability and brevity, the content-aware parts can be moved into a helper class to serve this purpose:

Wrapping it all up we’ll end up with the following:

So we can go ahead and use this extension function anywhere, without having to worry about manually getting rid of the listener and leaking memory.

Approaching similar problems in this lifecycle-aware way results in slightly shorter, more readable, and safer presentation classes.

That being said, I’m leaving you with the above steps, so you can go ahead and try them for yourself. Questions, suggestions, or any examples in which this proposed solution fixed your memory leak problems are welcome and encouraged, so feel free to share them in the comments.

Happy coding!