0
# State Management
1
2
Core state management functionality providing reactive state holders and automatic change detection. The state system enables building dynamic UIs that automatically recompose when data changes.
3
4
## Capabilities
5
6
### MutableState Creation
7
8
Creates mutable state holders that trigger recomposition when their values change.
9
10
```kotlin { .api }
11
/**
12
* Creates a MutableState<T> initialized with the given value
13
* @param value Initial value for the state
14
* @return MutableState that triggers recomposition on value changes
15
*/
16
fun <T> mutableStateOf(value: T): MutableState<T>
17
18
/**
19
* Creates a MutableState<T> with a specific SnapshotMutationPolicy
20
* @param value Initial value for the state
21
* @param policy Custom equality policy for change detection
22
* @return MutableState with custom mutation policy
23
*/
24
fun <T> mutableStateOf(
25
value: T,
26
policy: SnapshotMutationPolicy<T>
27
): MutableState<T>
28
```
29
30
**Usage Examples:**
31
32
```kotlin
33
import androidx.compose.runtime.*
34
35
@Composable
36
fun StateExample() {
37
// Basic mutable state
38
var counter by remember { mutableStateOf(0) }
39
var text by remember { mutableStateOf("") }
40
var isVisible by remember { mutableStateOf(true) }
41
42
// Custom objects
43
var user by remember { mutableStateOf(User("", "")) }
44
45
// Lists
46
var items by remember { mutableStateOf(listOf<String>()) }
47
}
48
49
data class User(val name: String, val email: String)
50
```
51
52
### Derived State
53
54
Creates computed state that recalculates when its dependencies change.
55
56
```kotlin { .api }
57
/**
58
* Creates a State<T> that recalculates when dependencies change
59
* @param calculation Function that computes the derived value
60
* @return State that automatically updates when dependencies change
61
*/
62
fun <T> derivedStateOf(calculation: () -> T): State<T>
63
64
/**
65
* Creates a State<T> with a custom SnapshotMutationPolicy
66
* @param policy Custom equality policy for change detection
67
* @param calculation Function that computes the derived value
68
* @return State with custom derived computation policy
69
*/
70
fun <T> derivedStateOf(
71
policy: SnapshotMutationPolicy<T>,
72
calculation: () -> T
73
): State<T>
74
```
75
76
**Usage Examples:**
77
78
```kotlin
79
@Composable
80
fun DerivedStateExample() {
81
var firstName by remember { mutableStateOf("") }
82
var lastName by remember { mutableStateOf("") }
83
84
// Derived state automatically recalculates when firstName or lastName change
85
val fullName by remember {
86
derivedStateOf { "$firstName $lastName".trim() }
87
}
88
89
val isValidName by remember {
90
derivedStateOf { fullName.length >= 2 }
91
}
92
93
TextField(value = firstName, onValueChange = { firstName = it })
94
TextField(value = lastName, onValueChange = { lastName = it })
95
Text("Full name: $fullName")
96
Button(enabled = isValidName) { Text("Submit") }
97
}
98
```
99
100
### State Interfaces
101
102
Core interfaces for state management.
103
104
```kotlin { .api }
105
/**
106
* Read-only state holder
107
*/
108
interface State<out T> {
109
/** Current value of the state */
110
val value: T
111
}
112
113
/**
114
* Mutable state holder that triggers recomposition on changes
115
*/
116
interface MutableState<T> : State<T> {
117
/** Current mutable value of the state */
118
override var value: T
119
120
/**
121
* Returns a new component1 for destructuring declarations
122
* @return Current value
123
*/
124
operator fun component1(): T
125
126
/**
127
* Returns a new component2 for destructuring declarations
128
* @return Setter function for the state
129
*/
130
operator fun component2(): (T) -> Unit
131
}
132
133
/**
134
* Default implementation of MutableState using the snapshot system
135
*/
136
interface SnapshotMutableState<T> : MutableState<T> {
137
/** The SnapshotMutationPolicy used by this state */
138
val policy: SnapshotMutationPolicy<T>
139
}
140
```
141
142
### Property Delegates
143
144
Kotlin property delegate support for convenient state access.
145
146
```kotlin { .api }
147
/**
148
* Property delegate getter for State<T>
149
* @param thisObj The object containing the property (unused)
150
* @param property Metadata about the property (unused)
151
* @return Current value of the state
152
*/
153
operator fun <T> State<T>.getValue(
154
thisObj: Any?,
155
property: KProperty<*>
156
): T
157
158
/**
159
* Property delegate setter for MutableState<T>
160
* @param thisObj The object containing the property (unused)
161
* @param property Metadata about the property (unused)
162
* @param value New value to set
163
*/
164
operator fun <T> MutableState<T>.setValue(
165
thisObj: Any?,
166
property: KProperty<*>,
167
value: T
168
): Unit
169
```
170
171
**Usage Examples:**
172
173
```kotlin
174
@Composable
175
fun PropertyDelegateExample() {
176
// Using property delegates with 'by'
177
var name by remember { mutableStateOf("") }
178
var age by remember { mutableStateOf(0) }
179
180
// Equivalent to:
181
// val nameState = remember { mutableStateOf("") }
182
// var name: String
183
// get() = nameState.value
184
// set(value) { nameState.value = value }
185
}
186
```
187
188
### Snapshot Flow Integration
189
190
Convert state reads into Kotlin coroutine Flows.
191
192
```kotlin { .api }
193
/**
194
* Creates a Flow that emits the result of block whenever observed state changes
195
* @param block Function that reads state and produces values
196
* @return Flow that emits when any observed state changes
197
*/
198
fun <T> snapshotFlow(block: () -> T): Flow<T>
199
```
200
201
**Usage Examples:**
202
203
```kotlin
204
@Composable
205
fun FlowIntegrationExample() {
206
var searchQuery by remember { mutableStateOf("") }
207
208
LaunchedEffect(Unit) {
209
snapshotFlow { searchQuery }
210
.debounce(300)
211
.collect { query ->
212
if (query.isNotEmpty()) {
213
performSearch(query)
214
}
215
}
216
}
217
}
218
```
219
220
### Persistent State Management
221
222
State management that survives process death and configuration changes, essential for iOS applications.
223
224
```kotlin { .api }
225
/**
226
* Creates persistent state that survives process death and configuration changes
227
* Equivalent to remember but persists across app restarts
228
* @param value Initial value for the state
229
* @param saver Custom Saver for serialization, uses auto-saver if null
230
* @return MutableState that persists across process death
231
*/
232
@Composable
233
fun <T> rememberSaveable(
234
vararg inputs: Any?,
235
saver: Saver<T, out Any>? = null,
236
init: () -> T
237
): T
238
239
/**
240
* Creates persistent mutable state with initial value
241
* @param value Initial value for the state
242
* @param saver Custom Saver for serialization
243
* @return MutableState that persists across process death
244
*/
245
@Composable
246
fun <T> rememberSaveable(
247
value: T,
248
saver: Saver<T, out Any>? = null
249
): MutableState<T>
250
```
251
252
**Usage Examples:**
253
254
```kotlin
255
@Composable
256
fun PersistentStateExample() {
257
// Survives iOS app backgrounding and termination
258
var userName by rememberSaveable { mutableStateOf("") }
259
var userId by rememberSaveable { mutableStateOf(0) }
260
261
// Custom object with custom saver
262
var userProfile by rememberSaveable(
263
saver = UserProfileSaver
264
) { mutableStateOf(UserProfile()) }
265
266
TextField(
267
value = userName,
268
onValueChange = { userName = it },
269
label = { Text("Username") }
270
)
271
}
272
273
object UserProfileSaver : Saver<UserProfile, Bundle> {
274
override fun restore(value: Bundle): UserProfile? =
275
UserProfile.fromBundle(value)
276
277
override fun SaverScope.save(value: UserProfile): Bundle? =
278
value.toBundle()
279
}
280
```
281
282
### Async State Production
283
284
Create state from asynchronous data sources like network calls or databases.
285
286
```kotlin { .api }
287
/**
288
* Creates state that is produced by an async operation
289
* @param initialValue Initial value while async operation is running
290
* @param key1 Key that triggers recreation of the producer
291
* @param producer Suspend function that produces the state value
292
* @return State that updates when async operation completes
293
*/
294
@Composable
295
fun <T> produceState(
296
initialValue: T,
297
key1: Any?,
298
producer: suspend ProduceStateScope<T>.() -> Unit
299
): State<T>
300
301
/**
302
* Scope for produceState operations
303
*/
304
interface ProduceStateScope<T> : MutableState<T>, CoroutineScope {
305
/** Awaits the coroutine to complete before disposing */
306
suspend fun awaitDispose(onDispose: () -> Unit)
307
}
308
```
309
310
**Usage Examples:**
311
312
```kotlin
313
@Composable
314
fun AsyncStateExample(userId: String) {
315
val userState by produceState(
316
initialValue = User.Empty,
317
key1 = userId
318
) {
319
// Suspend function that loads user data
320
value = userRepository.loadUser(userId)
321
}
322
323
val networkState by produceState(
324
initialValue = NetworkState.Loading
325
) {
326
try {
327
val data = apiService.fetchData()
328
value = NetworkState.Success(data)
329
} catch (e: Exception) {
330
value = NetworkState.Error(e.message)
331
}
332
}
333
334
when (networkState) {
335
is NetworkState.Loading -> LoadingIndicator()
336
is NetworkState.Success -> DataDisplay(networkState.data)
337
is NetworkState.Error -> ErrorMessage(networkState.message)
338
}
339
}
340
```
341
342
### Flow to State Conversion
343
344
Convert Kotlin coroutine Flows to Compose State for reactive UI updates.
345
346
```kotlin { .api }
347
/**
348
* Collects values from a Flow and represents them as State
349
* @param initial Initial value before first emission
350
* @param context CoroutineContext for collection, uses current recomposition context by default
351
* @return State that reflects the latest Flow emission
352
*/
353
@Composable
354
fun <T> Flow<T>.collectAsState(
355
initial: T,
356
context: CoroutineContext = EmptyCoroutineContext
357
): State<T>
358
359
/**
360
* Collects values from a Flow as State with lifecycle awareness
361
* @param initial Initial value before first emission
362
* @param lifecycle Lifecycle to respect for collection
363
* @param minActiveState Minimum lifecycle state for active collection
364
* @param context CoroutineContext for collection
365
* @return State that reflects the latest Flow emission
366
*/
367
@Composable
368
fun <T> Flow<T>.collectAsStateWithLifecycle(
369
initial: T,
370
lifecycle: Lifecycle,
371
minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
372
context: CoroutineContext = EmptyCoroutineContext
373
): State<T>
374
```
375
376
**Usage Examples:**
377
378
```kotlin
379
@Composable
380
fun FlowStateExample() {
381
val viewModel: UserViewModel = viewModel()
382
383
// Collect Flow as State
384
val users by viewModel.usersFlow.collectAsState(initial = emptyList())
385
val isLoading by viewModel.loadingFlow.collectAsState(initial = false)
386
387
// Display users
388
LazyColumn {
389
items(users) { user ->
390
UserItem(user = user)
391
}
392
}
393
394
if (isLoading) {
395
LoadingOverlay()
396
}
397
}
398
399
class UserViewModel : ViewModel() {
400
private val _users = MutableStateFlow<List<User>>(emptyList())
401
val usersFlow: StateFlow<List<User>> = _users.asStateFlow()
402
403
private val _loading = MutableStateFlow(false)
404
val loadingFlow: StateFlow<Boolean> = _loading.asStateFlow()
405
}
406
```
407
408
## Advanced State Management
409
410
### Custom Mutation Policies
411
412
```kotlin { .api }
413
/**
414
* Policy for determining when state changes should trigger recomposition
415
*/
416
interface SnapshotMutationPolicy<T> {
417
/**
418
* Determines if the current and new values are equivalent
419
* @param a Current value
420
* @param b New value
421
* @return true if values are equivalent and shouldn't trigger recomposition
422
*/
423
fun equivalent(a: T, b: T): Boolean
424
425
/**
426
* Merges conflicting changes during snapshot conflicts
427
* @param previous Previous value
428
* @param current Current value
429
* @param applied Value being applied
430
* @return Merged value or null if merge is not possible
431
*/
432
fun merge(previous: T, current: T, applied: T): T?
433
}
434
435
/** Built-in policies */
436
object SnapshotMutationPolicy {
437
/** Uses structural equality (==) for comparison */
438
fun <T> structuralEquality(): SnapshotMutationPolicy<T>
439
440
/** Uses referential equality (===) for comparison */
441
fun <T> referentialEquality(): SnapshotMutationPolicy<T>
442
443
/** Never considers values equivalent, always triggers recomposition */
444
fun <T> neverEqual(): SnapshotMutationPolicy<T>
445
}
446
```
447
448
## Performance Considerations
449
450
- **State Scoping**: Keep state as close as possible to where it's used
451
- **Derived State**: Use `derivedStateOf` instead of `remember` for computed values
452
- **State Hoisting**: Move state up the composition tree only when needed for sharing
453
- **Mutation Policies**: Consider custom policies for complex objects to avoid unnecessary recompositions