


Две корутины могут прочитать один и тот же счётчик и записать одинаковое новое значение. Одно увеличение тогда потеряется. MutableStateFlow.update позволяет атомарно применить изменение к текущему состоянию. На Mentoring.digital рассмотрим это на небольшом состоянии экрана.
Выражение state.value = state.value.copy(...) читает и записывает значение отдельными операциями. Допустим, обе корутины видят count = 3. Каждая вычисляет 4, и итог остаётся 4 вместо ожидаемых 5. Это возможно, даже когда само чтение и сама запись потокобезопасны.
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
data class ScreenState(val count: Int = 0)
class CounterState {
private val mutable = MutableStateFlow(ScreenState())
val state = mutable.asStateFlow()
fun increment() {
mutable.update { old ->
old.copy(count = old.count + 1)
}
}
}
Метод вычисляет новое значение из актуального состояния. Снаружи доступен поток для чтения. Внутри лямбды остаётся вычисление, поскольку при конкурирующих изменениях update может выполнить её больше одного раза. Запись в базу, отправку события и другие побочные действия выполняйте отдельно.
В тесте запустите несколько корутин, которые вызывают increment(), дождитесь их завершения и сравните конечный count с числом вызовов. Подписчик StateFlow может пропустить промежуточные значения, поэтому для этой задачи сравнивайте финальное состояние. Если нужно обновлять сразу несколько связанных полей, поместите их в один объект состояния и меняйте одним вызовом.
Состояние экрана можно отработать на курсе по Android-разработке. Если в реальном проекте есть несколько источников обновлений, разберите их порядок с наставником по Kotlin.