Комбинация состояний в Jetpack Compose
К примеру мне нужно показать диалог считывания, я могу создать два состояния
var showDialog by remember { mutableStateOf(true) }
var progress by remember { mutableStateOf(0.5f) }
но мне не нравится создавать много состояний, тогда
open class ReadState {
val progress:Float = 0.0f
var isReading = false
}
val readState: MutableSharedFlow<ReadState> = MutableSharedFlow()
...
val readState by viewModel.readState.collectAsState(ReadState.Initial)
но теперь мне нужно создавать новый объект ReadState каждый раз когда я обновляю progress, даже учитывая что MutableSharedFlow может посылать тот же объект collectAsState() не делает рекомпозицию.
Какие еще есть варианты чтобы состояние было комплексное но и без создания многих объектов?
Ответы (1 шт):
для компоуза хорошим подходом является работать со стейтами.
т.е. вы делаете какой-то data class StateForMyFragment
где в полях описывается абсолютно все данные, которые вам нужные.
важное условие: все поля должны быть неизменными val
следующим шагом будет использование StateFlow
а не SharedFlow
основную разницу между этими видами горячих потоков почитайте отдельно. но ключевое сейчас - создаем StateFlow<StateForMyFragment>
все изменения в этом флоу выполняйте через state.update{it.copy($изменяем_наименованые_параметры)}
можно и _state.value = _state.value.copy()
, но через update
- покрасивее и более оптимизировано под капотом.
а через .copy()
- потому что у нас поля val
если в StateFlow
будут var
'ы, то их изменение никак не сообщат подписчикам "тут новое значение".
есть подозрение, что mutableStateOf
работает по такому же принципу и поэтому у вас
даже учитывая что MutableSharedFlow может посылать тот же объект collectAsState() не делает рекомпозицию.
но это не точно, в этот вопрос я не погружался
и в корневой compose-функции вызываем val mState by state.collectAsStateWithLifecycle()
(скорее всего еще надо будет импортировать
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.8.3")
из корневой compose-функции должно быть много выходов на мелкие compose-функции. чем больше их, чем они мельче - тем меньше будет ненужных рекомпозиций.
и уже в них передавайте данные из mState
таким подходом вы будете держать абсолютно всю информацию об экране в объекте одного класса.
получать (прослушивать / коллектить) будете только в одном месте - в корне. что в любом случае будет вызывать рекомпозицию всего экрана.
но если ваша compose-функция будет состоять из мелких (которые зависят от разных параметров mState
) то рекомпозицию будут происходить только в тех местах, где что-то поменялось (отдельные блоки).
данный подход являются частью MVI-паттерна. можете и про него почитать.