Что такое Kotlin Flow?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое Kotlin Flow?
Kotlin Flow — это библиотека для асинхронного потокового программирования (stream processing), которая позволяет работать с потоками данных, выделяя холодные потоки (cold streams). Flow — это фундаментальный инструмент в современной Android разработке для обработки асинхронных операций.
Основные концепции
Flow — это холодный поток:
fun simpleFlow(): Flow<Int> = flow {
for (i in 1..3) {
emit(i) // отправляем значение
}
}
// Поток начинает работу только когда кто-то подписывается
simpleFlow().collect { value ->
println(value) // 1, 2, 3
}
Холодный поток (Cold Stream):
- Выполняется для каждого subscriber отдельно
- Если никто не подписан — ничего не происходит
- Каждый subscriber получает свою копию потока
Типы потоков Flow
1. StateFlow — состояние (горячий поток):
class UserViewModel {
private val _state = MutableStateFlow<UserState>(Loading)
val state: StateFlow<UserState> = _state.asStateFlow()
fun loadUser(id: String) {
viewModelScope.launch {
_state.value = UserState.Success(user)
}
}
}
// StateFlow всегда имеет текущее значение
val currentState = userViewModel.state.value
2. SharedFlow — публикация для многих subscriber:
private val _events = MutableSharedFlow<Event>()
val events: SharedFlow<Event> = _events.asSharedFlow()
fun sendEvent(event: Event) {
viewModelScope.launch {
_events.emit(event)
}
}
3. Flow — холодный поток данных:
fun getUsers(): Flow<List<User>> = flow {
emit(userRepository.fetchUsers())
}
getUsers().collect { users ->
println(users)
}
Операторы для трансформации
map — преобразование значений:
flow {
emit(1)
emit(2)
}.map { it * 2 }
.collect { println(it) } // 2, 4
filter — фильтрация:
flow { 1..5 }
.filter { it % 2 == 0 }
.collect { println(it) } // 2, 4
flatMapLatest — отмена предыдущей операции:
queryFlow
.flatMapLatest { query ->
searchRepository.search(query)
}
.collect { results ->
updateUI(results)
}
combine — объединение потоков:
combine(
firstNameFlow,
lastNameFlow
) { firstName, lastName ->
"$firstName $lastName"
}.collect { fullName ->
println(fullName)
}
debounce — задержка после последнего значения:
queryFlow
.debounce(300) // ждём 300ms после последнего значения
.flatMapLatest { query ->
searchRepository.search(query)
}
.collect { results ->
showResults(results)
}
Жизненный цикл и область видимости
viewModelScope — автоматическая отмена:
class UserViewModel : ViewModel() {
fun observeUser(userId: String) {
viewModelScope.launch {
userRepository.getUser(userId)
.collect { user ->
_state.value = UserState.Success(user)
}
}
// При уничтожении ViewModel корутины автоматически отменяются
}
}
Lifecycle.repeatOnLifecycle — синхронизация с UI:
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
userViewModel.state.collect { state ->
render(state)
}
// Автоматически паузируется когда activity в background
}
}
Композиция Flow в Compose
@Composable
fun UserScreen(viewModel: UserViewModel) {
val user by viewModel.userFlow.collectAsState(initial = null)
if (user != null) {
Column {
Text(user.name)
Text(user.email)
}
}
}
Практический пример: поиск с debounce
class SearchViewModel(
private val searchRepository: SearchRepository
) : ViewModel() {
private val _query = MutableStateFlow("")
val results: Flow<List<SearchResult>> = _query
.debounce(300)
.distinctUntilChanged()
.flatMapLatest { query ->
if (query.isEmpty()) {
flowOf(emptyList())
} else {
searchRepository.search(query)
}
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.Lazily,
initialValue = emptyList()
)
fun updateQuery(newQuery: String) {
_query.value = newQuery
}
}
Ключевые преимущества Flow
- Отмена операций — встроена отмена через корутины
- Обработка ошибок — try-catch работают нативно
- Backpressure — управление скоростью выброса данных
- Легко тестировать — Flow предсказуем и синхронен в тестах
- Реактивная разработка — связывай потоки как конвейер
Flow изменил то, как мы разрабатываем Android приложения, став стандартом для асинхронного программирования наряду с RxJava.