It’s been a while since my last post! Actually, more than 4 years… The Android ecosystem has changed a lot during that time! Some new concepts were introduced, some old programming languages were left behind and we have to make the most out of this situation (as always). So, let’s get down to business!

What is a Flow? (briefly)

The flow is a “new” concept of doing asynchronous tasks. Flows are built on top of coroutines and I am sure you have heard about them. The difference between flows and coroutines is that, the first is meant to produce multiple values one after the other, while the second is meant to produce a single value.

Flows are really useful when you need continuous updates of your data – e.x. live updates of a table from a database.

Types of flows

Having just a single way of creating flows would have been easy, but that’s not the case! Actually, there are some situations where we need a more specific functionality than the one out of the box. Thus, there are three different types of flow constructors that can come in handy:

  • flow - that’s the default way of creating flows. This constructor creates a cold flow. You are probably wondering what actually a cold flow is, right? Well check this discussion. In order to “return / produce” a result we have to use the emit() method, which also ensures that the current scope is still active by calling ensureActive.
fun myFunction(): Flow<MyObject> = flow { emit(MyObject()) } 
  • CallbackFlow – this type of flow is useful when you want to convert a callback-based API into a flow. A good example for this is the Firebase SDK. If you want to listen to changes in a Firestore document, you have to use a callback. But what if your app’s architecture is based on flows? That’s right – callbackFlow is here to help! This flow is using channels under the hood. You can read about them here, because we will not get into details about them. An important thing when using this flow type is to make use of awaitClose. This argument is called when:
    • The flow consumer cancels the collection
    • The callback-based API invokes SendChannel.close

This is a great place to clean whatever it’s needed before closing the flow – e.x. unregister a callback.

  • ChannelFlow – the base flow type from which the CallbackFlow inherits most of its functionality. If you dig into its implementation, you will notice that the only difference with CallbackFlow is that channelFlow doesn’t throw an IllegalStateException in its collectTo method. Thus, we can conclude that its functionality is almost the same as CallbackFlow.

Resources

Feel free to share, comment & give your opinion on the topic!