Когда приложение должно реагировать на изменения данных — появление нового сообщения, обновление счёта или загрузку из базы — на помощь приходит Flow. Это инструмент языка Kotlin для работы с асинхронными последовательностями, который позволяет отказаться от колбэков и ручного управления потоками. В этом уроке мы рассмотрим, как использовать Flow в Android Studio, чтобы сделать приложение отзывчивым и современным.
Что такое Flow и зачем он нужен
Flow — это поток данных, который может испускать несколько значений, а не одно. В отличие от LiveData, он не привязан к жизненному циклу и даёт больше возможностей для преобразований. Вы можете создавать Flow в репозитории, применять операторы в ViewModel и собирать результат в интерфейсе. Главное преимущество — полная совместимость с корутинами и простая обработка ошибок.
Создание простого Flow
Самый лёгкий способ создать Flow — использовать билдер flow { }. Внутри вы можете вызывать emit(), чтобы отправить новое значение. Например, сделаем Flow, который раз в секунду выдаёт увеличивающееся число.
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
fun counterFlow(): Flow<Int> = flow {
var count = 0
while (true) {
delay(1000)
count++
emit(count)
}
}
Сбор данных из Flow в ViewModel
Чтобы получить значения из Flow, их нужно «собрать». В ViewModel это делается в корутине через collect. Результат можно сохранять в StateFlow или напрямую передавать в UI через collectAsState в Compose. Внутри viewModelScope вы можете использовать операторы, например, map, filter, catch.
class CounterViewModel : ViewModel() {
private val _counter = MutableStateFlow(0)
val counter = _counter.asStateFlow()
init {
viewModelScope.launch {
counterFlow().collect { value ->
_counter.value = value
}
}
}
}
Использование Flow в интерфейсе
В Jetpack Compose превратить Flow в состояние очень просто — достаточно вызвать collectAsState(). При каждом новом значении композиция обновится автоматически.
@Composable
fun CounterScreen(viewModel: CounterViewModel) {
val counter by viewModel.counter.collectAsState()
Text("Счётчик: $counter")
}
Операторы Flow
Flow поддерживает множество операторов, похожих на коллекционные. Например, map преобразует значения, filter отбирает нужные, flowOn меняет поток выполнения, а catch перехватывает ошибки. Эти операторы позволяют строить цепочки обработки данных прямо в репозитории, не засоряя ViewModel.
fun userFlow(): Flow<User> = flow {
emit(loadFromNetwork())
}.map { it.copy(name = it.name.uppercase()) }
.catch { emit(User("Гость")) }
.flowOn(Dispatchers.IO)
Подводя итог
Сегодняшний урок показал, как Flow упрощает реактивное программирование в Android Studio. Вы научились создавать потоки данных, обрабатывать их в ViewModel и отображать в Compose. Это важный шаг к построению надёжных и легко поддерживаемых приложений на Kotlin. Попробуйте заменить обычные колбэки в своём проекте на Flow — вы сразу почувствуете, насколько чище становится код.