Getting Started with Kotlin Flow

October 11, 2021 Publish By : EXPERT APP DEVS 4 min read Viewed By : 654
kotlin flow

If you are an Android developer and looking to develop an app asynchronously you might be using RxJava for that. RxJava has become one of the most important things to learn and use in Android.

A lot of people use Kotlin Coroutines. The New Kotlin Coroutine version released by Jetbrains came up with Flow API as part of it. With the help of Flow, you can handle a stream of data that emits values sequentially.

What are Flow APIs in Kotlin Coroutines?

Flow API is the best way to handle the stream of data asynchronously that executes in a sequential manner.

In RxJava, the Observables structure represents a stream of items. RxJava body does not execute until it is subscribed to by a subscriber. once it is subscribed, the subscriber starts getting the data items emitted. The same way follows in Flow works on the same condition where the code inside a flow builder does not run until the flow connection is done.

Start Integrating Flow APIs in your project

Add the following in the app's build.gradle,

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3"
and in the project's build.gradle add,

classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61"

for the settle flow setupFlow() I will emit items after a 500milliseconds delay.

fun setupFlow(){
    flow = flow {
        Log.d(TAG, "Start flow")
        (0..10).forEach {
            delay(500)
            Log.d(TAG, "Emitting $it")
            emit(it)

        }
    }.flowOn(Dispatchers.Default)
}

Now we are going to write a code for printing the values which we received from the flow.

private fun setupClicks() {
    button.setOnClickListener {
        CoroutineScope(Dispatchers.Main).launch {
            flow.collect {
                Log.d(TAG, it.toString())
            }
        }
    }
}

Migrating from LiveData to Kotlin’s Flow


What is Stateflow?

Stateflow is a state-holder observable flow that emits the current and new state updates to its collectors. Current state value can also be read through a value property. To update the state and send it to the flow, we assign a new value to the value property of the MutableStateFlow class.

Migration to Stateflow

app.gradle

dependencies{
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2'
}

  • Here we are launching a new coroutine and assuring that the given block is only executed when the fragment or activity is at least in a RESUMED state.
  • We start observing the Stateflow by collecting the flow in the main thread.

private val state = MutableStateFlow(PostsState()) (1)
fun initialize() {
  (2)
  ...
}

fun observeState(): StateFlow<PostsState> { (3)
    return state
}

private fun fetchPosts() {
    CoroutineScope(Dispatchers.IO).launch {
        val posts = repository.getPosts()

        val newState = getState().copy(
                loading = false,
                posts = posts
        )
        emitNewState(newState) (4)
    }
}
private fun emitNewState(newState: PostsState) {
    state.value = newState (5)
}
private fun getState() = state.value (6)

Here is the difference when we are using Stateflow:

  1. The MutableStateFlow constructor requires passing through an initial state.
  2. Due to this initial state passed in the constructor, we don’t need to do anything manually.
  3. Here we just changed the return type, note that for several reasons we don’t want to expose a MutableStateFlow, that’s why we are returning a Stateflow, which can only be collected/observed.
  4. One of the most important advantages: updating the value of a Stateflow is thread-safe, so we can update it from any coroutine scope, making our code simpler and cleaner, and less error-prone.
  5. As mentioned earlier, we don’t need to update the value in the main thread, the fragment or activity is responsible for collecting the flow data and flow into the main thread.
  6. Contrary to LiveData, StateFlow’s value can’t be nullable so we don't need to check the null value.
     

Need a consultation?

Drop us a line! We are here to answer your questions 24/7.