**State** (or UiState) model usually capture everything on a given screen that can change over time. This state is usually contained by a **State Holder** (e.g:- a `Component`, `ViewModel`, `Presenter` or whatever) and mutate that state over time by applying business logic
Scoping a State Holder to a Router
If you want your screen level state holder to be scoped to a given screen, use rememberOnRoute
This makes your instances survive configuration changes (on Android)
Holds-on the instance as long as it is in the backstack
class List
@Composable
fun ListScreen() {
val list: List = rememberOnRoute(List::class) { _ -> List() }
}
If you want this instance to be recomputed, you can also provide a key to it
class Details(val id: String)
@Composable
fun DetailsScreen(id: String) {
val details: Details = rememberOnRoute(Details::class, key = id) { _ -> Details(id) }
}
Integrating with Decompose Components
Integrating Decompose components works the same way. RouterContext can provide you a ComponentContext if needed be
import com.arkivanov.decompose.ComponentContext
class ListComponent(context: RouterContext): ComponentContext by context
@Composable
fun MyScreen() {
val listComponent: ListComponent = rememberOnRoute(ListComponent::class) { context ->
ListComponent(context)
}
}
Integrating with Android Architecture Component ViewModels
Integrating AAC ViewModels works the same way. You can scope ViewModels directly and these will be stay on the stack/page/slot as long it is needed
import androidx.lifecycle.ViewModel
class ListViewModel: ViewModel()
@Composable
fun ListScreen() {
val viewModel: ListViewModel = rememberOnRoute(type = ListViewModel::class) { ListViewModel() }
}
Restoring Initial State after System-initiated Process Death
Initial state is the first-ever state your screen is rendered with. This is usually the default state for your screen. However, if your app is being restored after system initiated process death, we want to derive the initial state from saved state of the previous process (instead of the default)
Within your State Holder, you can derive the initial state by using RouterContext.state. Make sure to point the supplier lambda back to your state flow so that it knows where to grab the latest state from to save
class List(context: RouterContext) {
private val initialState: ListState = context.state(ListState()) { states.value }
private val _state: MutableStateFlow<ListState> = MutableStateFlow(initialState)
val states: StateFlow<ListState> = _state
}
Integrating with Molecule
For Molecule, initial state can be provided to your moleculeFlow in conjunction with stateIn
class List(context: RouterContext) {
private val initialState: ListState = context.state(ListState()) { states.value }
val states: StateFlow<EquipmentSelectionState> = moleculeFlow(ContextClock) { ListPresenter() }
.stateIn(this, SharingStarted.Lazily, initialState)
}