StateFlow

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

Поток состояния, представленный интерфейсом StateFlow, применяется как способ наблюдения за изменением состояния в приложении. Каждый объект StateFlow используется для хранения одного значения, которое может меняться со временем, а также для уведомления системы об изменении этого значения. StateFlow ведет себя так же, как LiveData, за исключением того, что LiveData учитывает жизненный цикл и не требует начального значения.

Для создания объекта StateFlow можно использовать встроенную функцию MutableStateFlow(), в которую передается обязательное начальное значение и которая возвращает объект одноименного типа:

private val _stateFlow = MutableStateFlow(0)

Далее эта переменная будет использоваться для изменения текущего значения состояния из кода приложения. Затем для преобразование в StateFlow у объекта MutableStateFlow вызывается метод asStateFlow():

val stateFlow = _stateFlow.asStateFlow()

Для изменения состояния измненеия вносятся через свойство value объекта MutableStateFlow:

_stateFlow.value += 1

Когда поток активен, состояние можно использовать с помощью метода collectAsState() или напрямую с помощью функции collection() или collectLatest(). Рассмотрим небольшой пример:

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.material3.Button

import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.material3.Text
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.sp
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow


class MainActivity : ComponentActivity() {

    private val _stateFlow = MutableStateFlow(0)
    val stateFlow = _stateFlow.asStateFlow()
    fun increase() { _stateFlow.value += 1 }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Main(flow=stateFlow, onIncrease = ::increase)
        }
    }
}

@Composable
fun Main(flow: StateFlow<Int>, onIncrease: ()->Unit) {
    val count by flow.collectAsState()
    Column(Modifier.fillMaxSize()) {
        Text("$count", fontSize = 44.sp)
        Button(onClick = { onIncrease() }) {
            Text("Increase", fontSize = 22.sp)
        }
    }
}

Здесь определяем состояние потока StateFlow в виде переменных _stateFlow и stateFlow, а также определяет функцию increase() для изменения состояния.

Компонент Main получает текущее значение потока в переменную count с помощью метода stateFlow.collectAsState(). Для вывода текущего значения определен компонент Text. А компонент Button позволяет по нажатию запустить функциюincrease(), тем самым изменяя значение в потоке.

StateFlow в Jetpack Compose в Kotlin

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

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.material3.Button

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.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow


class MainActivity : ComponentActivity() {

    private val _stateFlow = MutableStateFlow(0)
    val stateFlow = _stateFlow.asStateFlow()
    fun increase() { _stateFlow.value += 1 }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Main(flow=stateFlow, onIncrease = ::increase)
        }
    }
}

@Composable
fun Main(flow: StateFlow<Int>, onIncrease: ()->Unit) {
    val count by flow.collectAsState()
    val messages = remember { mutableStateListOf<Int>()}
    LaunchedEffect(Unit) {
        flow.collect {
            messages.add(it)
        }
    }
    Column(Modifier.fillMaxSize()) {
        Text("$count", fontSize = 44.sp)
        Button(onClick = { onIncrease() }) {
            Text("Increase", fontSize = 22.sp)
        }
        LazyColumn {
            items(messages) {
                Text("Collected Value = $it",Modifier.padding(5.dp))
            }
        }
    }
}

Теперь в компоненте Main также определена еще одна переменная состояния - messages, которая хранит некоторый набор сообщений, связанных с состоянием stateFlow:

val messages = remember { mutableStateListOf<Int>()}

С помощью дополнительного компонента LaunchedEffect запускаем метод collect(), который собирает все новые зиначения из потока и добавляет их в список messages

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

В итоге при изменения значения по нажатию на кнопку также будет пополняться список messages, который выводится в LazyColumn:

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