This is the 7th day of my participation in the August Gwen Challenge.
An overview of
The so-called state can be simply understood as the change of a value in the application, such as a Boolean value, an array
In the business scene, it can be the text in the TextField, the state of animation execution, the user’s collection of goods are all states
We know that compose is a declarative UI, and that every time we reorganize the page, we reorganize the component, so we need to introduce state management, for example:
We click the button in the item of the commodity to collect the commodity, at this time, the collection state of the commodity changes, we need to restructure the UI to change the commodity into the collection state, at this time, we need to use the remember extension method to save the reorganization state. If you use the Boolean primitive, you will not be able to set the state of the component properly after reorganizing the UI.
Code examples (copy official code) :
@Composable
fun HelloContent(a) {
Column(modifier = Modifier.padding(16.dp)) {
OutlinedTextField(
value = "Input value",
onValueChange = { },
label = { Text("Name")})}}Copy the code
Running the above code, we can see that the contents of the TextFile do not change no matter how we enter the contents in the TextField. This is because we cannot save the state. The following code example can change the contents of the TextField normally
@Composable
fun textFieldStateHasTextShow(a){
var value by remember {// Save the state of the text displayed in the TextField
mutableStateOf("")
}
Box(modifier = Modifier.fillMaxSize(1f),contentAlignment = Alignment.Center) {
OutlinedTextField(
value = value,
onValueChange = {
value=it// The updated state is called back each time the content is entered to refresh and reorganize the UI
},
label = { Text("Name")})}}Copy the code
Common methods of state management
Remember to preserve state during reassembly
Composition functions can remember individual objects by using Remember, and the system stores the value remembered initially in the composition during initialization. Remember can be used to store both mutable and immutable objects
When the composable item is removed, the object that Remember stored is forgotten.
mutableStateOf
MutableStateOf creates observable MutableState
, for example: Data is a MutableState object
Whenever the data.value value changes, the system reorganizes the UI.
var data = remember {
mutableStateOf("")}Copy the code
Note: mutableStateOf must use the Remember nesting to reorganize the interface when data changes
RememberSaveable Save the configuration
Remember helps us store state when the interface is reorganized, while rememberSaveable helps us store state when configuration changes (recreating an activity or process).
Livedata, Flow, and RxJava convert to state
These three frameworks are the three commonly used android responsive development frameworks, and all support converting State objects. Take Flow as an example, the following code can convert a State:
val favorites = MutableStateFlow<Set<String>>(setOf())
val state = favorites.collectAsState()
Copy the code
State management
Stateful and stateless
A combination that saves state using the Remember, rememberSaveState methods is a stateful combination
Otherwise, it is stateless combination
State of ascension
The following code is the official code for status promotion:
In this example, HelloContent is stateless and its state is promoted to HelloScreen. HelloContent has two parameters: Name and onNameChange. Name is the state. Pass to HelloContent via the HelloScreen composition
Changes that occur in HelloContent cannot be handled by itself, and must be passed to HelloScreen for processing and reorganizing the interface.
This logic is called: states go down, events go up
@Composable
fun HelloScreen() {
var name by rememberSaveable { mutableStateOf("") }
HelloContent(name = name, onNameChange = { name = it })
}
@Composable
fun HelloContent(name: String, onNameChange: (String) -> Unit) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Hello, $name",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.h5
)
OutlinedTextField(
value = name,
onValueChange = onNameChange,
label = { Text("Name") }
)
}
}
Copy the code
How to store state
Remember from the rememberSaveable method that you can save a state in a Bundle. What if the rememberSaveable state is not available in a Bundle?
There are three ways to save non-bundle data (save after configuration changes)
Parcelize
Code examples:
@Parcelize
data class City(val name: String, val country: String) : Parcelable
@Composable
fun CityScreen(a) {
var selectedCity = rememberSaveable {
mutableStateOf(City("Madrid"."Spain"))}}Copy the code
MapSaver
data class City(val name: String, val country: String)
val CitySaver = run {
val nameKey = "Name"
val countryKey = "Country"
mapSaver(
save = { mapOf(nameKey to it.name, countryKey to it.country) },
restore = { City(it[nameKey] as String, it[countryKey] as String) }
)
}
@Composable
fun CityScreen(a) {
var selectedCity = rememberSaveable(stateSaver = CitySaver) {
mutableStateOf(City("Madrid"."Spain"))}}Copy the code
ListSaver
data class City(val name: String, val country: String)
val CitySaver = listSaver<City, Any>(
save = { listOf(it.name, it.country) },// The values stored in the array correspond sequentially to the properties in City
restore = { City(it[0] as String, it[1] as String) }
)
@Composable
fun CityScreen(a) {
var selectedCity = rememberSaveable(stateSaver = CitySaver) {
mutableStateOf(City("Madrid"."Spain"))}}Copy the code
State management source code analysis
remember
Remember for the first time read the source code, there may be a wrong understanding of the place (but someone has to go to see not), forgive me, welcome correction
- The main flow of the remember method call
The Remember method returns a MutableState object, which notifies the system to reorganize the UI when data is updated
RememberedValue is the logic for data transformation
- RememberedValue method resolution
Inserting: If we are inserting new nodes into the view number, inserting=true
Reusing: means being reused. My understanding is that the state is currently being reused, so avoid multiple fetches
- The reader.next method shares a piece of source code
fun next(): Any? {
if (emptyCount > 0 || currentSlot >= currentSlotEnd) return Composer.Empty
return slots[currentSlot++]
}
Copy the code
The currentSlot is the index of the state we want to get in the array. The compose build page is single threaded. The index gets from slots every time we call remember if the state already exists. Then we increment the currentSlot index by 1, so that when we call the last remember method the currentSlot index is exactly equal to the slots array.length-1