State hoisting helps keep your app organized by moving state out of UI parts. This makes your code easier to read and test.
0
0
State hoisting pattern in Android Kotlin
Introduction
When you want to share state between different UI components.
When you want to separate UI display from business logic.
When you want to make your UI components reusable and simple.
When you want to test your app logic without UI.
When you want to avoid duplicating state in multiple places.
Syntax
Android Kotlin
class MyViewModel : ViewModel() { private val _count = MutableStateFlow(0) val count: StateFlow<Int> = _count fun increment() { _count.value += 1 } } @Composable fun Counter(count: Int, onIncrement: () -> Unit) { Button(onClick = onIncrement) { Text("Count: $count") } }
State is stored outside the UI in a ViewModel or similar class.
The UI component receives state and events as parameters.
Examples
This ViewModel holds the count state and a function to change it.
Android Kotlin
class CounterViewModel : ViewModel() { private val _count = MutableStateFlow(0) val count: StateFlow<Int> = _count fun increment() { _count.value += 1 } }
This UI component shows the count and calls onIncrement when clicked.
Android Kotlin
@Composable
fun Counter(count: Int, onIncrement: () -> Unit) {
Button(onClick = onIncrement) {
Text("Count: $count")
}
}This screen connects the ViewModel state to the UI component.
Android Kotlin
@Composable
fun CounterScreen(viewModel: CounterViewModel = androidx.lifecycle.viewmodel.compose.viewModel()) {
val count by viewModel.count.collectAsState()
Counter(count = count, onIncrement = { viewModel.increment() })
}Sample App
This app shows a button with a count. When you tap the button, the count increases. The count state is kept in the ViewModel, not inside the button UI.
Android Kotlin
import androidx.compose.material.Button import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewmodel.compose.viewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow class CounterViewModel : ViewModel() { private val _count = MutableStateFlow(0) val count: StateFlow<Int> = _count fun increment() { _count.value += 1 } } @Composable fun Counter(count: Int, onIncrement: () -> Unit) { Button(onClick = onIncrement) { Text("Count: $count") } } @Composable fun CounterScreen(viewModel: CounterViewModel = viewModel()) { val count by viewModel.count.collectAsState() Counter(count = count, onIncrement = { viewModel.increment() }) } @Composable fun App() { CounterScreen() }
OutputSuccess
Important Notes
State hoisting improves testability by separating UI from logic.
Always pass state and event handlers as parameters to UI components.
Use ViewModel or similar classes to hold state outside UI.
Summary
State hoisting means moving state out of UI components.
UI components become simpler and reusable by receiving state and events as parameters.
ViewModel is a common place to hold state in Android apps.