Tree composition support and runtime infrastructure for Compose Multiplatform desktop applications with declarative UI development APIs.
—
Core state management APIs for creating reactive UI state that automatically triggers recomposition when values change. The Compose state system enables declarative UI updates through observable state holders.
The fundamental interfaces for state management in Compose.
/**
* Read-only state holder that can be observed by composables
*/
interface State<out T> {
val value: T
}
/**
* Mutable state holder that triggers recomposition when changed
*/
interface MutableState<T> : State<T> {
override var value: T
}Create mutable state instances that trigger recomposition when their values change.
/**
* Creates a mutable state holder with the specified initial value
* @param value Initial value for the state
* @param policy Mutation policy for detecting changes (default: structural equality)
* @return MutableState instance
*/
fun <T> mutableStateOf(
value: T,
policy: SnapshotMutationPolicy<T> = structuralEqualityPolicy()
): MutableState<T>Usage Examples:
import androidx.compose.runtime.*
import androidx.compose.runtime.derivedStateOf
@Composable
fun StateExample() {
// Create mutable state
val count = mutableStateOf(0)
val text = mutableStateOf("Hello")
// Access values
Text("Count: ${count.value}")
Text("Text: ${text.value}")
// Update values
Button(onClick = { count.value++ }) {
Text("Increment")
}
Button(onClick = { text.value = "Updated!" }) {
Text("Update Text")
}
}Use property delegation for cleaner syntax with state values.
/**
* Delegate operator for reading state values
*/
operator fun <T> State<T>.getValue(
thisObj: Any?,
property: KProperty<*>
): T
/**
* Delegate operator for writing mutable state values
*/
operator fun <T> MutableState<T>.setValue(
thisObj: Any?,
property: KProperty<*>,
value: T
)Usage Examples:
@Composable
fun DelegationExample() {
// Using delegation with 'by' keyword
var count by mutableStateOf(0)
var isEnabled by mutableStateOf(true)
var userName by mutableStateOf("")
// Direct access without .value
Text("Count: $count")
Text("Enabled: $isEnabled")
Button(
onClick = { count++ },
enabled = isEnabled
) {
Text("Click me")
}
TextField(
value = userName,
onValueChange = { userName = it }
)
}Preserve state across recompositions using the remember API.
/**
* Remembers a value across recompositions
* @param calculation Function to create the remembered value
* @return The remembered value
*/
@Composable
fun <T> remember(calculation: () -> T): T
/**
* Remembers a value with dependency keys for conditional invalidation
* @param key1 Dependency key - value is recalculated when this changes
* @param calculation Function to create the remembered value
* @return The remembered value
*/
@Composable
fun <T> remember(key1: Any?, calculation: () -> T): T
/**
* Remembers a value with multiple dependency keys
*/
@Composable
fun <T> remember(
key1: Any?,
key2: Any?,
calculation: () -> T
): T
/**
* Remembers a value with variable number of dependency keys
*/
@Composable
fun <T> remember(
vararg keys: Any?,
calculation: () -> T
): TUsage Examples:
@Composable
fun RememberExample(userId: String) {
// Remember state across recompositions
val counter by remember { mutableStateOf(0) }
// Remember with key - recalculated when userId changes
val userProfile by remember(userId) {
mutableStateOf(loadUserProfile(userId))
}
// Remember expensive computations
val expensiveData by remember(userId) {
mutableStateOf(performExpensiveCalculation(userId))
}
// Multiple keys
val complexState by remember(userId, counter) {
mutableStateOf(createComplexState(userId, counter))
}
}Control how the state system detects changes using mutation policies.
/**
* Policy interface for detecting state mutations
*/
interface SnapshotMutationPolicy<T> {
fun equivalent(a: T, b: T): Boolean
fun merge(previous: T, current: T, applied: T): T?
}
/**
* Built-in policy using structural equality (==)
*/
fun <T> structuralEqualityPolicy(): SnapshotMutationPolicy<T>
/**
* Built-in policy using referential equality (===)
*/
fun <T> referentialEqualityPolicy(): SnapshotMutationPolicy<T>
/**
* Policy that treats all values as different (always triggers updates)
*/
fun <T> neverEqualPolicy(): SnapshotMutationPolicy<T>Usage Examples:
@Composable
fun PolicyExample() {
// Default structural equality
var items by mutableStateOf(listOf("a", "b", "c"))
// Referential equality - only updates on reference change
var objectState by mutableStateOf(
MyObject("data"),
referentialEqualityPolicy()
)
// Never equal - always triggers updates
var alwaysUpdate by mutableStateOf(
getCurrentTimestamp(),
neverEqualPolicy()
)
}State that survives configuration changes and process death.
/**
* Remembers state that can survive configuration changes
* @param inputs Dependency keys for conditional restoration
* @param saver Custom saver for non-primitive types
* @param init Function to create initial value
* @return Saveable state value
*/
@Composable
fun <T> rememberSaveable(
vararg inputs: Any?,
saver: Saver<T, out Any> = autoSaver(),
init: () -> T
): TUsage Examples:
import androidx.compose.runtime.saveable.rememberSaveable
@Composable
fun SaveableExample() {
// Survives configuration changes
var text by rememberSaveable { mutableStateOf("") }
var count by rememberSaveable { mutableStateOf(0) }
// Custom saver for complex objects
var customObject by rememberSaveable(
saver = CustomObjectSaver
) {
mutableStateOf(CustomObject())
}
TextField(
value = text,
onValueChange = { text = it }
)
Button(onClick = { count++ }) {
Text("Count: $count")
}
}Create state that depends on other state values.
/**
* Creates derived state that updates when dependencies change
*/
@Composable
fun <T> derivedStateOf(calculation: () -> T): State<T>Usage Examples:
@Composable
fun DerivedStateExample() {
var firstName by remember { mutableStateOf("") }
var lastName by remember { mutableStateOf("") }
// Derived state automatically updates when dependencies change
val fullName by remember {
derivedStateOf { "$firstName $lastName".trim() }
}
val isFormValid by remember {
derivedStateOf {
firstName.isNotBlank() && lastName.isNotBlank()
}
}
Text("Full name: $fullName")
Button(
onClick = { saveUser(fullName) },
enabled = isFormValid
) {
Text("Save")
}
}Produce state from asynchronous sources.
/**
* Produces state from a suspending producer function
* @param initialValue Initial value while producer is running
* @param producer Suspending function that produces values
* @return State holding the produced value
*/
@Composable
fun <T> produceState(
initialValue: T,
vararg keys: Any?,
producer: suspend ProduceStateScope<T>.() -> Unit
): State<T>
/**
* Scope for producing state values
*/
interface ProduceStateScope<T> : MutableState<T>, CoroutineScope {
suspend fun awaitDispose(onDispose: () -> Unit)
}Usage Examples:
@Composable
fun ProduceStateExample(url: String) {
// Produce state from async operation
val imageState by produceState<ImageBitmap?>(null, url) {
value = loadImageFromUrl(url)
}
val userData by produceState(UserData.Loading, userId) {
try {
value = UserData.Success(loadUser(userId))
} catch (e: Exception) {
value = UserData.Error(e.message)
}
}
when (val data = userData) {
is UserData.Loading -> CircularProgressIndicator()
is UserData.Success -> UserProfile(data.user)
is UserData.Error -> ErrorMessage(data.message)
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-jetbrains-compose-runtime--runtime-desktop