SharedState

Последнее обновление: 20.04.2024

SharedFlow предоставляет более универсальный вариант потоковой передачи, чем StateFlow. Ключевые различия между StateFlow и SharedFlow заключаются в следующем:

  • При создании объекта SharedFlow начальное значение не указывается

  • SharedFlow позволяет получить значения, которые были отправлены до начала сбора данных

  • SharedFlow генерирует значения с помощью emit() вместо использования свойства value

Для создания объекта SharedFlow сначала вызывается функция MutableSharedFlow(), которая создает значение типа MutableSharedFlow:

public fun <T> MutableSharedFlow(
    replay: Int = 0,
    extraBufferCapacity: Int = 0,
    onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND
): MutableSharedFlow<T>

Эта функция принимает три параметра:

  • replay: количество значений, воспроизводимых новым подписчикам

  • extraBufferCapacity: количество значений, буферизуемых в дополнение к значению параметра replay. emit не приостанавливается, пока остается свободное пространство в буфере.

  • onBufferOverflow: настраивает действие отправки при переполнении буфера. Значения, отличные от BufferOverflow.SUSPEND, поддерживаются только в том случае, если replay больше 0 или extraBufferCapacity больше 0. Переполнение буфера может произойти только в том случае, если есть хотя бы один подписчик, который не готов принять новое значение. При отсутствии подписчиков сохраняются только самые последние значения воспроизведения, а поведение переполнения буфера никогда не срабатывает и не имеет никакого эффекта.

    Может принимать следующие значения:

    • DROP_LATEST: последнее значение удаляется, когда буфер заполнен, оставляя буфер неизменным при обработке новых значений.

    • DROP_OLDEST: рассматривает буфер как стек, где самое старое значение отбрасывается, чтобы освободить место для нового значения, когда буфер заполнен.

    • SUSPEND: поток приостанавливается, когда буфер заполнен.

После создания у значения MutableSharedFlow вызывается метод asSharedFlow() для получения ссылки SharedFlow.

private val _sharedFlow = MutableSharedFlow<Int>()
val sharedFlow = _sharedFlow.asSharedFlow()

Значения передаются в поток SharedFlow путем вызова метода emit() объекта MutableSharedFlow:

someCoroutineScope.launch {
    for (i in 1..5) {
        _sharedFlow.emit(i)
    }
}

Например, возьмем пример с StateFlow из прошлой статьи и изменим его, заменив StateFlow на SharedFlow:

package com.example.helloapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items

import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.material3.Text
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch


class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val _sharedFlow = MutableSharedFlow<Int>()
            val sharedFlow = _sharedFlow.asSharedFlow()

            val coroutineScope = rememberCoroutineScope()

            LaunchedEffect(Unit) {
                coroutineScope.launch() {
                    for (i in 1..5) {
                        _sharedFlow.emit(i)
                        delay(2000)
                    }
                }
            }

            Main(flow=sharedFlow)
        }
    }
}

@Composable
fun Main(flow: SharedFlow<Int>) {
    val count by flow.collectAsState(0)
    val messages = remember { mutableStateListOf<Int>()}
    LaunchedEffect(Unit) {
        flow.collect {
            messages.add(it)
        }
    }
    Column(Modifier.fillMaxSize()) {
        Text("$count", fontSize = 44.sp)

        LazyColumn {
            items(messages) {
                Text("Collected Value = $it",Modifier.padding(5.dp))
            }
        }
    }
}

Здесь вначале собственно определяем состояние SharedFlow:

val _sharedFlow = MutableSharedFlow<Int>()
val sharedFlow = _sharedFlow.asSharedFlow()

Для эммитирования значений в поток определяем контекст корутины:

val coroutineScope = rememberCoroutineScope()

И чтобы при запуске приложения началась генерация значений в поток, определяем компонент LaunchedEffect:

LaunchedEffect(Unit) {
    coroutineScope.launch() {
        for (i in 1..5) {
            _sharedFlow.emit(i)
            delay(2000)
        }
    }
}

В данном случае в поток поступают числа от 1 до 5 с задержкой в 2 секунды.

Для определения интерфейса определен компонент Main, который принимает поток SharedFlow. В этом компоненте сначала определяем состояние:

val count by flow.collectAsState(0)
val messages = remember { mutableStateListOf<Int>()}

Переменная count получает текущее значение потока. А переменная messages хранит список полученных из потока значений. Для сбора значений в messages определен компонент LaunchedEffect:

LaunchedEffect(Unit) {
    flow.collect {
        messages.add(it)
    }
}

Для отображения текущего значения из потока определен компонент Text, а для вывода всех полученных значений - компонент LazyList:

SharedFlow и хранение состояния потока в Jetpack Compose в Kotlin
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850