Handle Asynchronous Data Loading With New Kotlin Flow

Tram Ho

In this article, we will explore the problem, how to handle asynchronous cases when loading data, using flow in kotlin.

Coroutines

When we call an asynchronous funtion like calling a service, retrieving data from a database, reading files or whatever, we all need a callback to know when the activity is complete and can continue our next task, like updating the UI. user after data reception. It is good to perform such tasks but in real time it will not be easy.

For example, after receiving data from the server, if we need to filter the data based on some data we have to manipulate to get it from local and again, we need another callback, so the data is retrieves in a complicated way and the result lies in the explosion of callbacks.

This is where a factor called coroutines appears to solve the problem and no longer need to write callbacks for asynchronous funtions.

There's a great concept in coroutines called suspend funtion that will do all the work we need, and return the desired data after it's done.

This will save more effort instead of using callbacks, instead we will focus on business logic.

Suspend Functions

A suspending function is simply a function that can be paused and resumed at a later time, it can perform an extended operation and wait for it to complete without intercepting service calls, operations. move to database, or read a long file. The syntax of a suspend function is the same as for normal funtion except that the suspend keyword is added at the beginning. The great thing about suspending functions is that it can return any number of responses.

Let's look at how it works, for example, we have a suspend funtion foo that will return a list of responses as shown below.

Then we call it under flow as shown below

The story that happens here is, when we call suspend funtion foo, it will start executing one-by-one and wait after the completion of executions, it will return a list of responses. Thus, here we have to wait until all executions are completed and this is not an optimal solution. But we can do better, the next solution that Kotlin found is Channel.

Channel

Channel is understood as a pipeline, structure, where we send data on one side and receive data on the other side, as shown below.

To use the channel, we need to change a bit of code, instead of using List <Response> as a return type, we use ReceiveChannel <Response>, use produce instead of buildlist , and use send instead. addTo

And then, when using it in our flow, then we will get the channel instead of a list of responses, then perform iterations and print, we will do as below.

What makes the difference, let's see When we call the function foo, it will create a channel and return it immediately but will not start execution. Now we have 2 coroutine running, one emits data and the other observe it.

When we call the channel while iterating, the implementation is started and it will execute one of the first and return responses and then the second and the next, similar. Works as shown below:

So by using the channel, you no longer need to wait to complete all the operations. But there is a problem here, the channel is hot.

Let's recall earlier that two coroutines were running, one observation and one to emit, so what would happen if there was no observer or confusion or any exceptions?

We know the channel is like opening a network connection or reading a file that will use large resources and if there is no observer, the connection will open and search for the observer again.

That can be solved, but in the long run, it will not be optimistic, it will cause serious problems in debugging and testing in the long run. However, we will still have a better solution, it's time to use kotllin flow, our main character.

Kotlin Flow

A stable version of flow has been released. Flow not only addresses channel weaknesses but also provides many new features. To use flow in the example above, we just need to change something like the return type to Flow and use flow instead of produce , and inside flow we have to use emit like below.

Next, in the general function, we have to use collect on the result of the function foo. Must collect all elements emitted by foo through flow

What happens when we call the function foo, it will immediately return the result and then continue the next start, and so on until there is no more.

So here we see the flow is similar to the Channel, it emits data and receives until it is no longer available, but the big difference here is that Flow is cold. Even if there is no observer or by mistake or intent, the coroutine will not hold it because it will not start anything.

Flow introduces a behavior that responds to its function by issuing results after completion of execution, which is not the same as waiting to complete the entire list of requests.

Flow Is Declarative

When we call the function foo in the flow example, it creates a flow and returns it, so we can use some operators like map to make the flow declarative more like below.

Here if you are observer, funtion foo is not a suspend function, why? As stated earlier, it only identifies the flow object, then emits it immediately and only computes and runs when it has started to collect.

Flow Is Reactive

With this title, everyone will probably think of RxJava, yes, RxJava is a kind of start of reactive program in JVM, where Kotlint runs mostly. So why do we have to use flow?

Why Flow?

Let's look at an example, if you want to convert any object of type A to type B in RxJava, we have an operator called map . Yes, it works fine, but what if the conversion should be done asynchronously? We can use an operator called flatmapSingle .

But in Kotlin, we have an operator called map , this operator's conversion lambda is suspend modifier, and it makes the map usable in both synchronous or asynchronous work. We can avoid hundreds of operators like this by using Kotlin because Kotlin has a suspend function, where RxJava and others can't.


The concepts mentioned and explained in this article are included in the speech at KotlintConf 2019, Link: Asynchronous Data Streams with Kotlin Flow by Roman Elizarov

Thank you for reading, hello and see you again.

Source: https://medium.com/better-programming/asynchronous-data-loading-with-new-kotlin-flow-233f85ae1d8b

Share the news now

Source : Viblo