Как изменить источник данных потока состояний kotlin

#android #kotlin-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
  }
...
}
 

Этот образец взят из https://commonsware.com/AndExplore/ книга

Я могу придумать это решение, но я не уверен, что это лучший способ

 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
            }
    }
}
 

Итак, как мы можем реализовать этот сценарий с помощью потока состояний.

Комментарии:

1. Что-то в этом роде, вероятно, является правильным ответом. Если бы у нас этого не было filterMode , вы могли бы использовать stateIn() для преобразования Flow в a StateFlow . Или, если бы мы были готовы сказать, что states это указывало бы на разные объекты в разное время, вы могли бы использовать stateIn() . Но в этом случае мы хотим states быть одним и тем же объектом на протяжении всего RosterMotor жизненного цикла, и мы хотим заполнить его из разных источников на основе filterMode , так stateIn() что, вероятно , это неправильный ответ.

2. Однако вам нужно прекратить собирать старые Flow данные при переключении filterMode значений. Это, вероятно, включает в себя удержание Job того, что launch() возвращается, так что вы можете cancel() сделать это в рамках запуска следующего Flow коллектора. Обновление этой книги для использования StateFlow входит в мой список дел на конец этого года.

3. спасибо за предложение, я отменю предыдущую работу. Я использую stateIn в других местах, таких как val states = repository.find(modelId) .map { SingleModelViewState(it) } .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5000), initialValue = SingleModelViewState() )