MXF
MXF

Reputation: 79

StateFlow collects in one coroutine

I tried init three collects in one coroutines, but worked only first. Only when i set collects in different coroutines its work. Why?

  lifecycleScope.launch {
            launch {
                homeViewModel.dateStateFlow().collect { date ->
                    date?.let { calendar.text = date.toStringForView() }
                }
            }
            launch {
                homeViewModel.toStateFlow().collect { to ->
                    to?.let { cityTo.text = to.name }
                }
            }
            launch {
                homeViewModel.fromStateFlow().collect { from ->
                    from?.let { cityFrom.text = from.name }
                }
            }
        }

Upvotes: 1

Views: 2169

Answers (1)

Tenfour04
Tenfour04

Reputation: 93609

A StateFlow never completes, so collecting it is an infinite action. This is explained in the documentation of StateFlow. Coroutines are sequential, so if you call collect on a StateFlow, none of the code after that call in the coroutine will ever be reached.

Since collecting StateFlows and SharedFlows to update UI is a common occurrence, I use helper functions like this to make it more concise:

fun <T> LifecycleOwner.collectWhenStarted(flow: Flow<T>, firstTimeDelay: Long = 0L, action: suspend (value: T) -> Unit) {
    lifecycleScope.launch {
        delay(firstTimeDelay)
        lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
            flow.collect(action)
        }
    }
}

// Usage:

collectWhenStarted(homeViewModel.dateStateFlow()) { date ->
    date?.let { calendar.text = date.toStringForView() }
}

Upvotes: 6

Related Questions