StateFlow и SharedFlow — это API-интерфейсы Flow , которые позволяют потокам оптимально отправлять обновления состояния и передавать значения нескольким потребителям.
 StateFlow
 StateFlow — это наблюдаемый поток владельца состояния, который отправляет текущие и новые обновления состояния своим сборщикам. Текущее значение состояния также можно прочитать через его свойство value . Чтобы обновить состояние и отправить его в поток, присвойте новое значение свойству value класса MutableStateFlow .
 В Android StateFlow отлично подходит для классов, которым необходимо поддерживать наблюдаемое изменяемое состояние.
 Следуя примерам из потоков Kotlin , StateFlow можно предоставить из LatestNewsViewModel , чтобы View могло прослушивать обновления состояния пользовательского интерфейса и, по сути, обеспечивать сохранение состояния экрана при изменении конфигурации.
class LatestNewsViewModel(
    private val newsRepository: NewsRepository
) : ViewModel() {
    // Backing property to avoid state updates from other classes
    private val _uiState = MutableStateFlow(LatestNewsUiState.Success(emptyList()))
    // The UI collects from this StateFlow to get its state updates
    val uiState: StateFlow<LatestNewsUiState> = _uiState
    init {
        viewModelScope.launch {
            newsRepository.favoriteLatestNews
                // Update View with the latest favorite news
                // Writes to the value property of MutableStateFlow,
                // adding a new element to the flow and updating all
                // of its collectors
                .collect { favoriteNews ->
                    _uiState.value = LatestNewsUiState.Success(favoriteNews)
                }
        }
    }
}
// Represents different states for the LatestNews screen
sealed class LatestNewsUiState {
    data class Success(val news: List<ArticleHeadline>): LatestNewsUiState()
    data class Error(val exception: Throwable): LatestNewsUiState()
}
 Класс, ответственный за обновление MutableStateFlow является производителем, а все классы, собираемые из StateFlow являются потребителями. В отличие от холодного потока, созданного с помощью построителя flow , StateFlow является горячим : сбор данных из потока не запускает какой-либо код производителя. StateFlow всегда активен и находится в памяти, и он становится пригодным для сборки мусора только в том случае, если на него нет других ссылок из корня сборки мусора.
 Когда новый потребитель начинает сбор данных из потока, он получает последнее состояние в потоке и все последующие состояния. Вы можете найти такое поведение в других наблюдаемых классах, таких как LiveData .
 View прослушивает StateFlow как и любой другой поток:
class LatestNewsActivity : AppCompatActivity() {
    private val latestNewsViewModel = // getViewModel()
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        // Start a coroutine in the lifecycle scope
        lifecycleScope.launch {
            // repeatOnLifecycle launches the block in a new coroutine every time the
            // lifecycle is in the STARTED state (or above) and cancels it when it's STOPPED.
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                // Trigger the flow and start listening for values.
                // Note that this happens when lifecycle is STARTED and stops
                // collecting when the lifecycle is STOPPED
                latestNewsViewModel.uiState.collect { uiState ->
                    // New value received
                    when (uiState) {
                        is LatestNewsUiState.Success -> showFavoriteNews(uiState.news)
                        is LatestNewsUiState.Error -> showError(uiState.exception)
                    }
                }
            }
        }
    }
}
 Чтобы преобразовать любой поток в StateFlow , используйте промежуточный оператор stateIn .
StateFlow, Flow и LiveData
 StateFlow и LiveData имеют сходство. Оба являются наблюдаемыми классами-держателями данных и оба следуют одному и тому же шаблону при использовании в архитектуре вашего приложения.
 Однако обратите внимание, что StateFlow и LiveData ведут себя по-разному:
-  StateFlowтребует, чтобы исходное состояние было передано конструктору, аLiveDataэтого не делает.
-  LiveData.observe()автоматически отменяет регистрацию потребителя, когда представление переходит в состояниеSTOPPED, тогда как сбор изStateFlowили любого другого потока не прекращает сбор автоматически. Чтобы добиться такого же поведения, вам необходимо собрать поток из блокаLifecycle.repeatOnLifecycle.
 Делаем холодные потоки горячими с помощью shareIn
 StateFlow — это горячий поток — он остается в памяти до тех пор, пока поток собирается или пока существуют другие ссылки на него из корня сборки мусора. Вы можете превратить холодные потоки в горячие, используя оператор shareIn .
 Используя в качестве примера callbackFlow , созданный в потоках Kotlin , вместо того, чтобы каждый сборщик создавал новый поток, вы можете поделиться данными, полученными из Firestore, между сборщиками с помощью shareIn . Вам необходимо передать следующее:
-  CoroutineScope, используемый для совместного использования потока. Эта область должна существовать дольше, чем любой потребитель, чтобы общий поток оставался активным столько, сколько необходимо.
- Количество предметов, которые будут воспроизведены каждому новому коллекционеру.
- Политика стартового поведения.
class NewsRemoteDataSource(...,
    private val externalScope: CoroutineScope,
) {
    val latestNews: Flow<List<ArticleHeadline>> = flow {
        ...
    }.shareIn(
        externalScope,
        replay = 1,
        started = SharingStarted.WhileSubscribed()
    )
}
 В этом примере поток latestNews воспроизводит последний отправленный элемент новому сборщику и остается активным, пока работает externalScope и есть активные сборщики. Политика запуска SharingStarted.WhileSubscribed() сохраняет активность вышестоящего производителя, пока есть активные подписчики. Доступны и другие политики запуска, например SharingStarted.Eagerly для немедленного запуска источника или SharingStarted.Lazily для начала общего доступа после появления первого подписчика и сохранения активности потока навсегда.
Общий поток
 Функция shareIn возвращает SharedFlow — горячий поток, который передает значения всем получающим от него потребителям. SharedFlow — это широко настраиваемое обобщение StateFlow .
 Вы можете создать SharedFlow без использования shareIn . Например, вы можете использовать SharedFlow для отправки меток в остальную часть приложения, чтобы весь контент периодически обновлялся одновременно. Помимо получения последних новостей, вы также можете обновить раздел информации о пользователе коллекцией избранных тем. В следующем фрагменте кода TickHandler предоставляет SharedFlow , чтобы другие классы знали, когда обновлять его содержимое. Как и в случае с StateFlow , используйте в классе резервное свойство типа MutableSharedFlow для отправки элементов в поток:
// Class that centralizes when the content of the app needs to be refreshed
class TickHandler(
    private val externalScope: CoroutineScope,
    private val tickIntervalMs: Long = 5000
) {
    // Backing property to avoid flow emissions from other classes
    private val _tickFlow = MutableSharedFlow<Unit>(replay = 0)
    val tickFlow: SharedFlow<Event<String>> = _tickFlow
    init {
        externalScope.launch {
            while(true) {
                _tickFlow.emit(Unit)
                delay(tickIntervalMs)
            }
        }
    }
}
class NewsRepository(
    ...,
    private val tickHandler: TickHandler,
    private val externalScope: CoroutineScope
) {
    init {
        externalScope.launch {
            // Listen for tick updates
            tickHandler.tickFlow.collect {
                refreshLatestNews()
            }
        }
    }
    suspend fun refreshLatestNews() { ... }
    ...
}
 Вы можете настроить поведение SharedFlow следующими способами:
-  replayпозволяет повторно отправить ряд ранее отправленных значений новым подписчикам.
-  onBufferOverflowпозволяет указать политику, когда буфер заполнен элементами для отправки. Значением по умолчанию являетсяBufferOverflow.SUSPEND, что приводит к приостановке вызывающего объекта. Другие варианты:DROP_LATESTилиDROP_OLDEST.
 MutableSharedFlow также имеет свойство subscriptionCount , которое содержит количество активных сборщиков, чтобы вы могли соответствующим образом оптимизировать свою бизнес-логику. MutableSharedFlow также содержит функцию resetReplayCache если вы не хотите воспроизводить последнюю информацию, отправленную в поток.
Дополнительные ресурсы потока
- Kotlin работает на Android
- Тестирование потоков Kotlin на Android
- Что нужно знать об операторах ShareIn и StateIn Flow
- Миграция с LiveData на Kotlin Flow
- Дополнительные ресурсы для сопрограмм и потоков Kotlin
