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

В каком виде используется 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