Kotlin Flow: Best Practices
Since few months, @Geev, we used Kotlin Flow inside our Android application. It is a really beautiful library to use, it helps us to write efficient streams of data. The following few points are what we believe to be our base of best practices.
No Kotlin Flow 🙅♀️
This first point may be the simplest: do not use Kotlin Flow if you are not consuming streams.
Indeed, for one-shot requests, it’s preferably to apply suspended
functions. No need to create a stream when we only send data to a server or receive a data object from an API just one-time. No need to overkill your app 😉
Use catch operator 🕵️♀️
By using the catch
operator, we increase control and readability.
When we deal with a flow, we could have an unexpected error. In order to prevent our app to crash, we have to catch these kind of exceptions. A basic way would be to surround the flow with a try/catch
close.
However, it is better to catch the exception directly inside our flow with catch
. This operator catches upstream flows errors and can also emit new values to downstream flows. It makes our stream more concise too.
Play with launchIn 👩✈️
Prefer to decrease the verbosity of the flow collecting with launchIn
.
We often launch our flow collection in a CoroutineScope bounded to a lifecycle, as the ViewModel’s scope.
We might want to remove the outer brackets and to reduce this boilerplate.
launchIn
combines launch
and collect
. It is a final operator, and this is why we need to apply onEach
operator to get the data before collecting.
On a side note, in our previous snippet, if an error occurred in collect
, it was not caught. With the new implementation, the catch
operator is below onEach
, therefore it secures the collecting.
Inject Dispatcher in flowOn 🥷
We must inject Dispatcher to change the flows context.
Changing the context of flows is done using flowOn
. We could switch the execution of the upstream flows to IO Dispatcher as follows:
Hardcoded these Dispatchers can lead to unexpected behaviors when writing tests and to be very painful to control the flow’s context. Instead of the above, we should inject them and replace them in unit and instrumentation tests with a test dispatcher.
Expose immutable StateFlow 👮♀️
When updating a StateFlow value, we have to maintain the immutable state of this flow.
Do not directly use mutable StateFlow from other classes. This does not guarantees the flow’s state because it could be updated from another class. It might lead to unpleasant debug when something goes wrong.
We must ensure the centralization of the updating state in one class only making the debugging easier.
Best Practices 👨🎤
We follow these few tricks when using Kotlin Flow in our app. We thought that it improved our efficiency and the stability of our platform. These enhancements helped us for writing greater code and better tests.