1

I am migrating this code sample to StateFlow.

class RosterMotor(private val repo: ToDoRepository) : ViewModel() {
  private val _states = MediatorLiveData<RosterViewState>()
  val states: LiveData<RosterViewState> = _states
  private var lastSource: LiveData<RosterViewState>? = null

  init {
    load(FilterMode.ALL)
  }

  fun load(filterMode: FilterMode) {
    lastSource?.let { _states.removeSource(it) }

    val items =
      repo.items(filterMode).map { RosterViewState(it, filterMode) }.asLiveData()

    _states.addSource(items) { viewstate ->
      _states.value = viewstate
    }

    lastSource = items
  }
...
}

This sample is taken from https://commonsware.com/AndExplore/ book

I can think of this solution but I am not sure if this is the best way

private val _states = MutableStateFlow(RosterViewState())
val states: StateFlow<RosterViewState> = _states

init {
    load(ALL)
}

fun load(filterMode: FilterMode) {
    viewModelScope.launch {
        repository.items(filterMode).map { RosterViewState(it, filterMode) }
            .collect {
                _states.value = it
            }
    }
}

So how we can implement this scenario using StateFlow.

Vivart
  • 14,900
  • 6
  • 36
  • 74
  • 1
    Something like that probably is the right answer. If we did not have `filterMode`, you could use `stateIn()` to convert the `Flow` to a `StateFlow`. Or, if we were willing to say that `states` would point to different objects at different times, you could use `stateIn()`. But, in this case, we want `states` to be the same object throughout the `RosterMotor` lifecycle, and we want to populate it from varying sources based on `filterMode`, so `stateIn()` probably isn't the right answer. – CommonsWare Jul 10 '21 at 14:58
  • 1
    However, you need to stop collecting the old `Flow` when you switch `filterMode` values. That probably involves holding onto the `Job` that `launch()` returns, so you can `cancel()` it as part of launching the next `Flow` collector. Updating this book to use `StateFlow` is on my to-do list for later this year. – CommonsWare Jul 10 '21 at 14:59
  • thanks for the suggestion, I will cancel previous job. I am using stateIn in other places like `val states = repository.find(modelId) .map { SingleModelViewState(it) } .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5000), initialValue = SingleModelViewState() )` – Vivart Jul 10 '21 at 15:04

0 Answers0