1

This code invokes two methods on the same viewmodel and listens for updates. But only the first method completes, the second does not event trigger.

private fun initData() {
    lifecycleScope.launchWhenStarted {
        viewModel.incrementCount().collect {
            info { "Count: $it" }
        }

        viewModel.getAllTeams().collect {
            when (it) {
                is State.Success -> {
                    info { "Got teams with size: ${it.result}.size" }
                }
                is State.Error -> {
                    info { "Error getting teams: ${it.message}" }
                }
                State.Loading -> {
                    info { "Loading all teams" }
                }
            }
        }
    }
}

ViewModel

class DashboardViewModel : ViewModel(), com.droid.common.Logger {

fun incrementCount(): MutableStateFlow<Int> {
    val countState = MutableStateFlow(0)

    viewModelScope.launch {
        repeat(5) {
            countState.value = (it)
            delay(1000)
        }
    }

    return countState
}

fun getAllTeams(): MutableStateFlow<State> {
    val state = MutableStateFlow<State>(State.None)

    state.value = State.Loading

    viewModelScope.launch {
        try {
            val allTeams = FootballAPIClient.apiService.getAllTeams()
            state.value = State.Success(allTeams)
        } catch (exception: Exception) {
            error { "Error getting all teams: ${exception.message}" }
            state.value = State.Error(exception.message.toString())
        }
    }

    return state
}

However, calling them with separate lifecycleScope works

private fun initData() {
    lifecycleScope.launchWhenStarted {
        viewModel.incrementCount().collect {
            info { "Count: $it" }
        }
    }

    lifecycleScope.launchWhenStarted {
        viewModel.getAllTeams().collect {
            when (it) {
                is State.Success -> {
                    info { "Got teams with size: ${it.result}.size" }
                }
                is State.Error -> {
                    info { "Error getting teams: ${it.message}" }
                }
                State.Loading -> {
                    info { "Loading all teams" }
                }
            }
        }
    }
}

I can't seem to understand this behavior, anybody knows why?

Veeresh Charantimath
  • 4,641
  • 5
  • 27
  • 36

1 Answers1

0

You will need different coroutines, since collect() is a suspending function that suspends until your Flow terminates.

The problem with launchWhenStarted is that while your newly emitted items will not be processed your producer will still run in the background.

For collecting multiple flows the currently recommended way is:

lifecycleScope.launch {
    lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
        launch {
          viewModel.incrementCount().collect { ... }   
        }
    
        launch {
            viewModel.getAllTeams().collect { ... }
        }
    }
}
che10
  • 2,176
  • 2
  • 4
  • 11