This blog is about the library that came into existence after reading Chris Banes blog series on Suspending over Views. The intention behind this blog is to throw some light on this library and get feedback from the community. So enjoy this short one! :)

Android ❤️s callback. All framework and jetpack libraries APIs uses it to notify events, but it becomes messy when you have nested callbacks. It’s difficult to understand and scale. Also, the chances of bugs are very high when you’re dealing with nested callbacks.

The good thing is we can easily avoid it through Kotlin’s coroutine APIs. callback-ktx is an attempt to wrap the potential framework and jetpack callback-based APIs into suspending extension functions. In case of multiple callbacks, it exposes Flow to observe all callbacks.

It would be kinda redundant if I explain all the benefits you will get by wrapping callbacks into suspending functions as Chris Banes blog series already covered them nicely. If you haven’t read it I would suggest reading it before continuing this one.

It is not difficult at all to wrap callback-based APIs into suspending function. What was challenging though was to go through all framework and jetpack APIs and figure out which API could be benefited. Let’s see what this library is capable of as of now.

What is it?

Currently, the library covers the following APIs from framework and jetpack.

  • Animation
  • Location
  • RecyclerView
  • Sensor
  • View
  • Widget(TextView)

Let’s see one example of observing location updates.

To get the last location all you need to do is to call awaitLastLocation which is an extension function over FusedLocationProviderClient

viewLifecycleOwner.lifecycleScope.launch {
  val location = fusedLocationProviderClient.awaitLastLocation() // Suspend coroutine
  // Use location

To observe location update it exposes flow of location.

viewLifecycleOwner.lifecycleScope.launch {
  fusedLocationProviderClient.locationFlow(locationRequest, lifecycleOwner).collect { location ->
    // Consume location

Note that extension takes lifecycle owner along with location request. This makes flow lifecycle aware so it won’t fire location updates while the app is in the background. You can visit the library on GitHub to see more examples.

There are two essential things while wrapping callback into suspending function to avoid potential memory leak and unwanted resource use by coroutines

  1. If coroutine gets cancelled for some reason, the callback needs to be unregistered.
  2. If an async operation for which callback is expected gets cancelled, the coroutine needs to be terminated.

The library takes care of both of these. Also, Callback extensions are divided across different modules based on the category they fall under. For example, all framework APIs would fall under the core module. Anything not related to the framework is in its separate module. So depending on the need user can depend on a specific maven artifact.

What’s next?

As I mentioned earlier, the big challenge while working on this library was to figure out all APIs that could be benefited. I would love to see contributions from the community in terms of filing issues for new extensions, bug fixes and optimisations. You can find repo here

Until next time 👋🏻

This was originally posted on Google Developer Expert Medium publication