0
0
Android Kotlinmobile~7 mins

State hoisting pattern in Android Kotlin

Choose your learning style9 modes available
Introduction

State hoisting helps keep your app organized by moving state out of UI parts. This makes your code easier to read and test.

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.