← Назад к вопросам

Что такое Kotlin Flow?

2.2 Middle🔥 171 комментариев
#Kotlin основы#Многопоточность и асинхронность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое 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.