← Назад к вопросам
В каком виде используется Flow
1.7 Middle🔥 191 комментариев
#Kotlin основы#Многопоточность и асинхронность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
В каком виде используется Flow
Flow — это тип данных из Kotlin Coroutines, который эмитит поток значений асинхронно. Flow используется для представления реактивного потока данных, который может быть собран и обработан с помощью корутин. Это холодный поток, означающий что код выполняется только когда есть collector (подписчик). Flow идеален для работы с потоками данных в Android разработке.
Основные типы Flow
// 1. StateFlow — хранит состояние и эмитит текущее значение новым подписчикам
val userState: StateFlow<User> = MutableStateFlow(defaultUser)
// 2. SharedFlow — делится между несколькими подписчиками
val events: SharedFlow<Event> = MutableSharedFlow()
// 3. Flow — обычный холодный поток
fun getUsersFlow(): Flow<List<User>> = flow {
val users = fetchUsersFromDatabase()
emit(users)
}
// 4. ChannelFlow — поток с поддержкой backpressure
fun processDataFlow(): ChannelFlow<Int> = channelFlow {
for (i in 1..100) {
send(i)
}
}
StateFlow
StateFlow — это переменная, которая всегда имеет значение и эмитит обновления:
class UserViewModel : ViewModel() {
private val _userState = MutableStateFlow<User?>(null)
val userState: StateFlow<User?> = _userState.asStateFlow()
fun loadUser(id: String) {
viewModelScope.launch {
val user = fetchUser(id) // Сетевой запрос
_userState.value = user // Обновляем состояние
}
}
}
// В UI слое (Activity/Fragment)
class UserActivity : AppCompatActivity() {
private val viewModel: UserViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch {
// StateFlow автоматически работает с lifecycle
viewModel.userState.collect { user ->
updateUI(user)
}
}
}
}
SharedFlow
SharedFlow — это событийный поток для коммуникации между компонентами:
class EventBus {
private val _events = MutableSharedFlow<Event>()
val events: SharedFlow<Event> = _events.asSharedFlow()
suspend fun postEvent(event: Event) {
_events.emit(event)
}
}
// Использование
class FirstFragment : Fragment() {
private val eventBus by inject<EventBus>()
fun onButtonClick() {
viewLifecycleOwner.lifecycleScope.launch {
eventBus.postEvent(UserClickedEvent(userId = 123))
}
}
}
class SecondFragment : Fragment() {
private val eventBus by inject<EventBus>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.launch {
eventBus.events.collect { event ->
when (event) {
is UserClickedEvent -> handleUserClicked(event.userId)
}
}
}
}
}
Обычный Flow
Обычный Flow используется для одноразовых потоков данных:
class UserRepository {
fun getUsersFlow(): Flow<List<User>> = flow {
// Холодный поток — выполняется только когда есть collector
val users = fetchUsersFromDatabase()
emit(users) // Эмитим данные
}
fun getUsersPaginated(pageSize: Int): Flow<List<User>> = flow {
var currentPage = 0
while (true) {
val users = fetchUsersPage(currentPage, pageSize)
if (users.isEmpty()) break
emit(users)
currentPage++
}
}
}
// Использование
class UserViewModel(private val repository: UserRepository) : ViewModel() {
val users: Flow<List<User>> = repository.getUsersFlow()
.stateIn(viewModelScope, SharingStarted.Lazily, emptyList())
fun observeUsers() {
viewModelScope.launch {
repository.getUsersFlow()
.filter { it.isNotEmpty() }
.map { it.sortedBy { user -> user.name } }
.collect { users ->
updateUI(users)
}
}
}
}
ChannelFlow для backpressure
fun sendDataWithBackpressure(): ChannelFlow<Int> = channelFlow {
for (i in 1..1000) {
send(i) // Автоматически замедляет отправку если collector медленный
delay(100)
}
}
// Использование
viewModelScope.launch {
sendDataWithBackpressure().collect { value ->
println("Received: $value")
}
}
Трансформация Flow
class DataViewModel : ViewModel() {
private val _query = MutableStateFlow("")
val searchResults: Flow<List<Item>> = _query
.debounce(300) // Ждём 300мс после последнего изменения
.distinctUntilChanged() // Пропускаем дублирующиеся значения
.flatMapLatest { query ->
if (query.isBlank()) {
flowOf(emptyList())
} else {
searchRepository.search(query) // Flow<List<Item>>
}
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = emptyList()
)
fun updateQuery(newQuery: String) {
_query.value = newQuery
}
}
Практический пример: ViewModel с Flow
class ChatViewModel(
private val chatRepository: ChatRepository
) : ViewModel() {
// Состояние сообщений
val messages: StateFlow<List<Message>> = chatRepository
.getMessagesFlow()
.stateIn(viewModelScope, SharingStarted.Lazily, emptyList())
// События (ошибки, уведомления)
private val _events = MutableSharedFlow<ChatEvent>()
val events: SharedFlow<ChatEvent> = _events.asSharedFlow()
fun sendMessage(text: String) {
viewModelScope.launch {
try {
chatRepository.sendMessage(text)
} catch (e: Exception) {
_events.emit(ChatEvent.Error(e.message ?: "Unknown error"))
}
}
}
}
// UI слой
class ChatFragment : Fragment() {
private val viewModel: ChatViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Подписываемся на состояние
viewLifecycleOwner.lifecycleScope.launch {
viewModel.messages.collect { messages ->
adapter.submitList(messages)
}
}
// Слушаем события
viewLifecycleOwner.lifecycleScope.launch {
viewModel.events.collect { event ->
when (event) {
is ChatEvent.Error -> showError(event.message)
}
}
}
}
}
Сравнение типов Flow
| Тип | Горячий/Холодный | Состояние | Использование |
|---|---|---|---|
| Flow | Холодный | Нет | Одноразовые потоки, реактивные операции |
| StateFlow | Горячий | Да (текущее значение) | UI состояние (MVVM) |
| SharedFlow | Горячий | Нет | События, broadcast сообщения |
| ChannelFlow | Холодный | Нет | Backpressure, производитель-потребитель |
Правила использования Flow
- StateFlow для состояния, которое всегда имеет значение
- SharedFlow для событий и broadcast коммуникации
- Flow для трансформаций и фильтрации данных
- ChannelFlow когда нужна обработка backpressure
- Всегда собирай Flow в
lifecycleScopeилиviewModelScope