Kotlin Flow Simplified

Kotlin Flow Simplified



According to Android documentation, a?flow?is a type that can emit multiple values sequentially. A flow is conceptually a stream of data that can be computed asynchronously and Provides intermediate operators?to modify the stream without consuming values. ( So basically it's an alternate to RxJava. Bye-bye RxJava :) )

Flows?by nature are not lifeCycle aware, unlike LiveData. This makes sense as it is not a part of the android component but a type from kotlin language. However, this can be resolved by responsibly collecting flow values within lifecycleScopes via coroutines and other ways.

?Flow is?declarative/cold: It can only be executed on collection. and?there are hot flows as well?(SharedFlow and Stateflow?). (cold: Stops emission when any collector is not active. Hot: it remains in memory as long as the flow is collected or as long as any other references to it exist from a garbage collection root.)

Flow collection can also be made lifecycle aware using below :

1.?repeatonLifeCycle(LifecycleState.STARTED) or flowWithLifeCycle(LifeCycleState.STARTED)

2. .asLiveData()

Flow Builder

  • Flow builder is used for creating a Flow. After creating a flow you can emit the data using?emit()?function.
  • When you create a flow it will generate a?Cold Flow?because it starts emitting value only when someone has subscribed to it.
  • In the case of cold flow, If multiple consumers subscribe to the Flow then the Producer will execute it multiple times. In the below case, multiple network calls happen to fetch the latest news by the different-different consumers.


val favoriteRecipe: Flow<List<NigerianRecipe>> 
        recipesRemoteDataSource.latestRecipes
            // Intermediate operation to filter the list of favorite recipes
            .map { news -> news.filter { userData.isFavoriteRecipe(it) } }
            // Intermediate operation to save the latest news in the cache
            .onEach { recipes -> saveInCache(recipes) }        


Note:?Here Producer can not emit() the values from different CoroutineContext, It should be emitted through the same coroutine context.

State Flow

  • State Flow is similar to normal flow but it holds the state. When you initialize the state flow you always need to tell the initial value of state flow. Hence state flow will have always a value.
  • State flow is?Hot Flow?because it starts emitting values even though there is no consumer.
  • State flow always has an initial value, replays one most recent value to new subscribers, does not buffer any more values, but keeps the last emitted one.
  • All methods of state flow are?thread-safe?and can be safely invoked from concurrent coroutines without external synchronization.
  • You can convert Cold flow to state flow using?stateIn()?operator.
  • When you collect state flow through?collect{}?and if the consumer gets recreated due to configuration change?it will re-call?collect{}



class CounterModel 
    private val _counter = MutableStateFlow(0) // private mutable state flow
    val counter = _counter.asStateFlow() // publicly exposed as read-only state flow

    fun inc() {
        _counter.update { count -> count + 1 } // atomic, safe for concurrent use
    }
}
        


Shared Flow

  • Shared Flow is the hot flow that emits all value to all consumers in a broadcast fashion.
  • You can convert Cold flow to shared flow using?stateIn()?operator.
  • All methods of shared flow are?thread-safe?and can be safely invoked from concurrent coroutines without external synchronization.
  • A shared flow keeps a specific number of the most recent values in its?replay cache. Every new subscriber first gets the values from the replay cache and then gets new emitted values. The maximum size of the replay cache is specified when the shared flow is created by the?replay?parameter.
  • A default implementation of a shared flow that is created with?MutableSharedFlow()?constructor function without parameters has no replay cache nor additional buffer.
  • When you collect shared flow through?collect{}?and if the consumer gets recreated due to configuration change?it will not re-call?collect{}



private val _events = MutableSharedFlow<Event>() // private mutable shared fl
    val events = _events.asSharedFlow() // publicly exposed as read-only shared flow

    suspend fun produceEvent(event: Event) {
        _events.emit(event) // suspends until all subscribers receive it
    }
        


Thanks for reading, if you find this helpful please leave alike. I also appreciate feedbacks





要查看或添加评论,请登录

Paul Ndibe的更多文章

社区洞察

其他会员也浏览了