#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
в aStateFlow
. Или, если бы мы были готовы сказать, что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() )