callbackFlow - Callback to Flow API in Kotlin

Authors
callbackFlow - Callback to Flow API in Kotlin

callbackFlow is a Flow builder in Kotlin that converts any Callback into a Flow. We send each value using trySend(), and we unregister the callback inside the awaitClose block.

In this blog, we will learn how to convert any Callback to Flow API in Kotlin using callbackFlow.

I am Amit Shekhar, Founder @ Outcome School, I have taught and mentored many developers, and their efforts landed them high-paying tech jobs, helped many tech companies in solving their unique problems, and created many open-source libraries being used by top companies. I am passionate about sharing knowledge through open-source, blogs, and videos.

I teach AI and Machine Learning, and Android at Outcome School.

Join Outcome School and get a high-paying tech job:

Let's get started.

This blog is a part of the series I have written on Flow API in Kotlin:

We use many libraries in our Android Project that provides the callback way to use instead of the Flow API way. As nowadays, we all have started using Kotlin Coroutines Flow API in our projects, so it becomes our responsibility to implement things in a way that supports Flow API.

So, we need to learn how to convert any Callback to Flow API in Kotlin using callbackFlow. And, this is the topic of this blog.

Here, I will take an example of a LocationManager just for the sake of understanding.

Assume that we can use LocationManager and listen to the changes in location as below:

// create a location listener
val locationListener = object : LocationListener {

    override fun onLocationUpdate(location: Location) {
        // do something with the updated location
    }

}

// register for location updates
LocationManager.registerForLocation(locationListener)

// unregister in onDestroy()
LocationManager.unregisterForLocation(locationListener)

Here, we have a LocationListener through which we get the onLocationUpdate callback.

A quick note for you

No matter which tech domain you work in, get familiar with these topics:

  • LLM
  • RAG
  • MCP
  • Agent
  • Fine-tuning
  • Quantization

We put it all together in one video:

AI Engineering Explained: LLM, RAG, MCP, Agent, Fine-Tuning, and Quantization

No need to stop reading - bookmark it and watch later when you get time. Future you will thank you.

Now, let's get back to the topic.

Now, we want to use this LocationManager in the Flow API way.

Let's do this by creating a function which returns Flow<Location> as below:

fun getLocationFlow(): Flow<Location> {
    return callbackFlow {

        val locationListener = object : LocationListener {

            override fun onLocationUpdate(location: Location) {
                trySend(location)
            }

        }

        LocationManager.registerForLocation(locationListener)

        awaitClose {
            LocationManager.unregisterForLocation(locationListener)
        }

    }
}

Now, it's time to understand what we have done to convert the Callback to Flow API.

We have followed the following steps to convert the Callback to Flow API in Kotlin:

  • Create a function to return the Flow<Location>.
  • Use callbackFlow as the return block.
  • Use trySend() for the location updates.
  • Use awaitClose block to unregister.

Now, we can use the above function as below:

launch {
    getLocationFlow()
    .collect { location ->
        // do something with the updated location
    }
}

This is how we can convert any callback to Flow API in Kotlin using callbackFlow.

So, today we learned how to convert any callback to Flow API and use them.

If we want to go deep into the Flow API, callbackFlow, structured concurrency, and how Coroutines internals power all of this in real Android projects, check out the Android Program by Outcome School.

Stay updated: Subscribe to our newsletter to get our latest AI and Machine Learning blogs straight to your inbox.

Frequently Asked Questions

When should we use callbackFlow?

We should use callbackFlow when a library provides the callback way instead of the Flow API way. A good example is a LocationManager that keeps giving us location updates through a listener. Wrapping it with callbackFlow lets us use it in the Flow API way.

How do we emit values from a callback inside callbackFlow?

We call trySend() inside the callback. For example, inside onLocationUpdate, we call trySend(location). Each value sent this way is emitted into the Flow that our function returns.

Why do we need the awaitClose block in callbackFlow?

We use the awaitClose block to unregister the callback. In the LocationManager example, we call unregisterForLocation inside awaitClose.

How do we use the Flow returned by callbackFlow?

We call collect on the Flow inside a coroutine started with launch. Every location update sent from the callback reaches the collect block. There, we do something with the updated location.

That's it for now.

Thanks

Amit Shekhar
Founder @ Outcome School

You can connect with me on:

Follow Outcome School on:

Read all of our high-quality blogs here.