สถานะในแอปคือค่าใดก็ตามที่เปลี่ยนแปลงได้เมื่อเวลาผ่านไป ซึ่งเป็นคำจำกัดความที่กว้างมากและครอบคลุมทุกอย่างตั้งแต่ฐานข้อมูล Room ไปจนถึงตัวแปรในคลาส
แอป Android ทั้งหมดจะแสดงสถานะให้ผู้ใช้เห็น ตัวอย่างสถานะในแอป Android มีดังนี้
- แถบแสดงสถานะที่แสดงเมื่อสร้างการเชื่อมต่อเครือข่ายไม่ได้
- บล็อกโพสต์และความคิดเห็นที่เกี่ยวข้อง
- ภาพเคลื่อนไหวแบบริปเปิลบนปุ่มที่เล่นเมื่อผู้ใช้คลิกปุ่ม
- สติกเกอร์ที่ผู้ใช้สามารถวาดทับรูปภาพได้
Jetpack Compose ช่วยให้คุณระบุตำแหน่งและวิธีจัดเก็บและใช้สถานะในแอป Android ได้อย่างชัดเจน คู่มือนี้จะเน้นที่การเชื่อมต่อระหว่างสถานะและ Composable รวมถึง API ที่ Jetpack Compose มีให้เพื่อทำงานกับสถานะ
สถานะและองค์ประกอบ
Compose เป็นแบบประกาศ ดังนั้นวิธีเดียวที่จะอัปเดตได้คือการเรียกใช้ Composable เดียวกันกับอาร์กิวเมนต์ใหม่ อาร์กิวเมนต์เหล่านี้แสดงถึงสถานะ UI ทุกครั้งที่มีการอัปเดตสถานะ ระบบจะจัดองค์ประกอบใหม่ ด้วยเหตุนี้ สิ่งต่างๆ เช่น TextField จึงไม่อัปเดตโดยอัตโนมัติเหมือนในมุมมองที่อิงตาม XML แบบบังคับ คุณต้องแจ้งสถานะใหม่ให้ Composable ทราบอย่างชัดเจนเพื่อให้ Composable อัปเดตตามสถานะดังกล่าว
@Composable private fun HelloContent() { Column(modifier = Modifier.padding(16.dp)) { Text( text = "Hello!", modifier = Modifier.padding(bottom = 8.dp), style = MaterialTheme.typography.bodyMedium ) OutlinedTextField( value = "", onValueChange = { }, label = { Text("Name") } ) } }
หากคุณเรียกใช้โค้ดนี้และพยายามป้อนข้อความ คุณจะเห็นว่าไม่มีอะไรเกิดขึ้น เนื่องจาก TextField จะไม่อัปเดตตัวเอง แต่จะอัปเดตเมื่อพารามิเตอร์ value มีการเปลี่ยนแปลง ซึ่งเป็นเพราะวิธีการทำงานของ Composition และ Recomposition ใน Compose
การคอมโพสครั้งแรก: การสร้างคอมโพสิชันโดยการเรียกใช้คอมโพสิเบิลเป็นครั้งแรก
การจัดองค์ประกอบใหม่: การเรียกใช้ Composable อีกครั้งเพื่ออัปเดตองค์ประกอบเมื่อข้อมูลมีการเปลี่ยนแปลง
ดูข้อมูลเพิ่มเติมเกี่ยวกับ Composition เริ่มต้นและ Recomposition ได้ที่การคิดใน Compose
สถานะใน Composable
ฟังก์ชันที่ประกอบกันได้สามารถใช้ remember API เพื่อจัดเก็บออบเจ็กต์ในหน่วยความจำ ค่าที่คำนวณโดย remember จะจัดเก็บไว้ใน Composition ระหว่างการคอมโพสครั้งแรก และระบบจะแสดงค่าที่จัดเก็บไว้ระหว่างการคอมโพสใหม่ remember ใช้เพื่อจัดเก็บทั้งออบเจ็กต์ที่เปลี่ยนแปลงได้และเปลี่ยนแปลงไม่ได้
mutableStateOf จะสร้าง MutableState<T> ที่สังเกตได้ ซึ่งเป็นประเภทที่สังเกตได้ที่ผสานรวมกับรันไทม์ของ Compose
interface MutableState<T> : State<T> {
override var value: T
}
การเปลี่ยนแปลงใดๆ ใน value จะกำหนดเวลาการจัดองค์ประกอบใหม่ของฟังก์ชันที่ประกอบกันได้ซึ่งอ่าน value
การประกาศออบเจ็กต์ MutableState ใน Composable ทำได้ 3 วิธีดังนี้
val mutableState = remember { mutableStateOf(default) }var value by remember { mutableStateOf(default) }val (value, setValue) = remember { mutableStateOf(default) }
การประกาศเหล่านี้เทียบเท่ากัน และมีไว้เป็นไวยากรณ์ที่เข้าใจง่ายสำหรับการใช้สถานะที่แตกต่างกัน คุณควรเลือกวิธีที่สร้างโค้ดที่อ่านง่ายที่สุดใน Composable ที่คุณกำลังเขียน
ไวยากรณ์ผู้รับมอบสิทธิ์ by ต้องมีการนำเข้าต่อไปนี้
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
คุณสามารถใช้ค่าที่จดจำไว้เป็นพารามิเตอร์สำหรับ Composable อื่นๆ หรือแม้แต่เป็นตรรกะในคำสั่งเพื่อเปลี่ยน Composable ที่แสดงได้ ตัวอย่างเช่น หากคุณไม่ต้องการแสดงคำทักทายหากชื่อว่างเปล่า ให้ใช้สถานะในคำสั่ง if ดังนี้
@Composable fun HelloContent() { Column(modifier = Modifier.padding(16.dp)) { var name by remember { mutableStateOf("") } if (name.isNotEmpty()) { Text( text = "Hello, $name!", modifier = Modifier.padding(bottom = 8.dp), style = MaterialTheme.typography.bodyMedium ) } OutlinedTextField( value = name, onValueChange = { name = it }, label = { Text("Name") } ) } }
แม้ว่า remember จะช่วยให้คุณคงสถานะไว้ได้ตลอดการจัดองค์ประกอบใหม่ แต่สถานะจะไม่คงอยู่ตลอดการเปลี่ยนแปลงการกำหนดค่า ซึ่งคุณต้องใช้ rememberSaveable rememberSaveable จะบันทึกค่าที่บันทึกได้ใน Bundle โดยอัตโนมัติ สำหรับค่าอื่นๆ คุณสามารถส่งออบเจ็กต์ Saver ที่กำหนดเองได้
สถานะประเภทอื่นๆ ที่รองรับ
Compose ไม่กำหนดให้คุณต้องใช้ MutableState<T> เพื่อเก็บสถานะ แต่รองรับประเภทที่สังเกตได้อื่นๆ ก่อนที่จะอ่านประเภทที่สังเกตได้อีกประเภทหนึ่งใน Compose คุณต้องแปลงประเภทดังกล่าวเป็น State<T> เพื่อให้ Composable สามารถจัดองค์ประกอบใหม่โดยอัตโนมัติเมื่อสถานะเปลี่ยนแปลง
Compose มาพร้อมกับฟังก์ชันในการสร้าง State<T> จากประเภทที่สังเกตได้ทั่วไปซึ่งใช้ในแอป Android ก่อนใช้การผสานรวมเหล่านี้ ให้เพิ่มอาร์ติแฟกต์ที่เหมาะสมดังนี้
Flow:collectAsStateWithLifecycle()collectAsStateWithLifecycle()จะรวบรวมค่าจากFlowในลักษณะที่รับรู้วงจรชีวิต ซึ่งช่วยให้แอปประหยัดทรัพยากรของแอปได้ ซึ่งแสดงค่าล่าสุดที่ส่งมาจากStateของ Compose ใช้ API นี้เป็นวิธีที่แนะนำในการรวบรวมโฟลว์ในแอป Androidต้องมีทรัพยากร Dependency ต่อไปนี้ในไฟล์
build.gradle(ควรเป็น 2.6.0-beta01 ขึ้นไป)
Kotlin
dependencies {
...
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.11.0")
}
ดึงดูด
dependencies {
...
implementation "androidx.lifecycle:lifecycle-runtime-compose:2.11.0"
}
-
collectAsStateคล้ายกับcollectAsStateWithLifecycleเนื่องจากจะรวบรวมค่าจากFlowและเปลี่ยนเป็น ComposeStateด้วยใช้
collectAsStateสำหรับโค้ดที่ไม่ขึ้นอยู่กับแพลตฟอร์มแทนcollectAsStateWithLifecycleซึ่งใช้ได้กับ Android เท่านั้นไม่จำเป็นต้องใช้ทรัพยากร Dependency เพิ่มเติมสำหรับ
collectAsStateเนื่องจากมีอยู่ในcompose-runtime -
observeAsState()เริ่มสังเกตLiveDataนี้และแสดงค่าโดยใช้Stateต้องมีทรัพยากร Dependency ต่อไปนี้ในไฟล์
build.gradle
Kotlin
dependencies {
...
implementation("androidx.compose.runtime:runtime-livedata:1.12.1")
}
ดึงดูด
dependencies {
...
implementation "androidx.compose.runtime:runtime-livedata:1.12.1"
}
-
subscribeAsState()เป็นฟังก์ชันส่วนขยายที่เปลี่ยนรูปแบบสตรีมแบบรีแอ็กทีฟของ RxJava2 (เช่นSingle,Observable,Completable) เป็นStateของ Composeต้องมีทรัพยากร Dependency ต่อไปนี้ในไฟล์
build.gradle
Kotlin
dependencies {
...
implementation("androidx.compose.runtime:runtime-rxjava2:1.12.1")
}
ดึงดูด
dependencies {
...
implementation "androidx.compose.runtime:runtime-rxjava2:1.12.1"
}
-
subscribeAsState()เป็นฟังก์ชันส่วนขยายที่เปลี่ยนรูปแบบสตรีมแบบรีแอ็กทีฟของ RxJava3 (เช่นSingle,Observable,Completable) เป็นStateของ Composeต้องมีทรัพยากร Dependency ต่อไปนี้ในไฟล์
build.gradle
Kotlin
dependencies {
...
implementation("androidx.compose.runtime:runtime-rxjava3:1.12.1")
}
ดึงดูด
dependencies {
...
implementation "androidx.compose.runtime:runtime-rxjava3:1.12.1"
}
แบบเก็บสถานะเทียบกับแบบไม่เก็บสถานะ
Composable ที่ใช้ remember เพื่อจัดเก็บออบเจ็กต์จะสร้างสถานะภายใน ซึ่งทำให้ Composable เก็บสถานะ HelloContent เป็นตัวอย่างของ Composable ที่เก็บสถานะเนื่องจากเก็บและแก้ไขสถานะ name ภายใน ซึ่งจะเป็นประโยชน์ในสถานการณ์ที่ผู้เรียกไม่จำเป็นต้องควบคุมสถานะและสามารถใช้ได้โดยไม่ต้องจัดการสถานะด้วยตนเอง อย่างไรก็ตาม Composable ที่มีสถานะภายในมักจะนำมาใช้ซ้ำได้น้อยกว่าและทดสอบได้ยากกว่า
คอมโพสิเบิลแบบไม่เก็บสถานะคือคอมโพสิเบิลที่ไม่ได้เก็บสถานะใดๆ ไว้ วิธีทั่วไปในการทำให้ไม่มีสถานะคือการใช้การย้ายสถานะ
เมื่อพัฒนา Composable ที่นำกลับมาใช้ใหม่ได้ คุณมักจะต้องการแสดงทั้งเวอร์ชันที่เก็บสถานะและไม่เก็บสถานะของ Composable เดียวกัน เวอร์ชันที่เก็บสถานะจะสะดวกสำหรับผู้เรียกที่ไม่สนใจสถานะ และเวอร์ชันที่ไม่เก็บสถานะจำเป็นสำหรับผู้เรียกที่ต้องการควบคุมหรือยกสถานะ
การย้ายสถานะ
การย้ายสถานะใน Compose เป็นรูปแบบการย้ายสถานะไปยังผู้เรียกของ Composable เพื่อทำให้ Composable ไม่มีสถานะ รูปแบบทั่วไปสำหรับการย้ายสถานะใน Jetpack Compose คือการแทนที่ตัวแปรสถานะด้วยพารามิเตอร์ 2 รายการ ได้แก่
value: T: ค่าปัจจุบันที่จะแสดงonValueChange: (T) -> Unit: เหตุการณ์ที่ขอให้เปลี่ยนค่า โดยที่Tคือค่าใหม่ที่เสนอ
อย่างไรก็ตาม คุณไม่ได้จำกัดอยู่เพียง onValueChange เท่านั้น หากเหตุการณ์ที่เฉพาะเจาะจงมากขึ้นเหมาะกับ Composable คุณควรกำหนดเหตุการณ์เหล่านั้นโดยใช้ Lambda
สถานะที่โฮสต์ด้วยวิธีนี้มีคุณสมบัติที่สำคัญบางอย่างดังนี้
- แหล่งข้อมูลที่เชื่อถือได้เพียงแหล่งเดียว: การย้ายสถานะแทนการทำซ้ำจะช่วยให้มั่นใจได้ว่ามีแหล่งข้อมูลที่เชื่อถือได้เพียงแหล่งเดียว ซึ่งจะช่วยหลีกเลี่ยงข้อบกพร่องได้
- Encapsulated: เฉพาะ Composable ที่เก็บสถานะเท่านั้นที่แก้ไขสถานะของตนเองได้ ซึ่งเป็นเรื่องภายในทั้งหมด
- แชร์ได้: สถานะที่ยกขึ้นสามารถแชร์กับ Composable หลายรายการได้ หากต้องการอ่าน
nameใน Composable อื่น การยกจะช่วยให้คุณทำเช่นนั้นได้ - Interceptable: ผู้เรียกใช้ Composable แบบไม่เก็บสถานะสามารถเลือกที่จะเพิกเฉยหรือแก้ไขเหตุการณ์ก่อนที่จะเปลี่ยนสถานะได้
- แยกกัน: สถานะสำหรับ Composable แบบไม่เก็บสถานะอาจจัดเก็บไว้ที่ใดก็ได้ ตัวอย่างเช่น ตอนนี้คุณสามารถย้าย
nameไปยังViewModelได้แล้ว
ในกรณีตัวอย่าง คุณจะดึง name และ onValueChange ออกจาก HelloContent และย้ายขึ้นไปในโครงสร้างต้นไม้ไปยัง Composable HelloScreen ที่เรียกใช้ HelloContent
@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.bodyMedium ) OutlinedTextField(value = name, onValueChange = onNameChange, label = { Text("Name") }) } }
การยกสถานะออกจาก HelloContent จะช่วยให้พิจารณาเกี่ยวกับ Composable, นำไปใช้ซ้ำในสถานการณ์ต่างๆ และทดสอบได้ง่ายขึ้น HelloContent จะแยกออกจากวิธีจัดเก็บสถานะ การแยกส่วนหมายความว่าหากคุณแก้ไขหรือแทนที่ HelloScreen คุณไม่จำเป็นต้องเปลี่ยนวิธีติดตั้งใช้งาน HelloContent
รูปแบบที่สถานะลดลงและเหตุการณ์เพิ่มขึ้นเรียกว่าโฟลว์ข้อมูลแบบทิศทางเดียว ในกรณีนี้ สถานะจะลดลงจาก HelloScreen เป็น HelloContent และเหตุการณ์จะเพิ่มขึ้นจาก HelloContent เป็น HelloScreen การทำตามโฟลว์ข้อมูลแบบทิศทางเดียวจะช่วยให้คุณแยก Composable ที่แสดงสถานะใน UI ออกจากส่วนต่างๆ ของแอปที่จัดเก็บและเปลี่ยนสถานะได้
- ควรยกสถานะขึ้นไปที่อย่างน้อยระดับบนสุดร่วมที่ต่ำที่สุดของ Composable ทั้งหมดที่ใช้สถานะ (อ่าน)
- ควรยกสถานะขึ้นไปที่อย่างน้อยระดับสูงสุดที่อาจมีการเปลี่ยนแปลง (เขียน)
- หากสถานะ 2 สถานะเปลี่ยนแปลงเพื่อตอบสนองต่อเหตุการณ์เดียวกัน สถานะเหล่านั้นควรยกขึ้นพร้อมกัน
คุณสามารถยกสถานะให้สูงกว่าที่กฎเหล่านี้กำหนดได้ แต่การยกสถานะต่ำเกินไปจะทำให้การทำตามโฟลว์ข้อมูลแบบทิศทางเดียวทำได้ยากหรือเป็นไปไม่ได้เลย
ดูข้อมูลเพิ่มเติมได้ที่หน้าตำแหน่งที่จะยกสถานะ
การคืนค่าสถานะใน Compose
API rememberSaveable ทำงานคล้ายกับ remember เนื่องจากจะคงสถานะไว้ตลอดการจัดองค์ประกอบใหม่ รวมถึงตลอดการสร้างกิจกรรมหรือกระบวนการใหม่โดยใช้กลไกสถานะอินสแตนซ์ที่บันทึกไว้ ตัวอย่างเช่น กรณีนี้จะเกิดขึ้นเมื่อหมุนหน้าจอ
วิธีจัดเก็บสถานะ
ระบบจะบันทึกข้อมูลทุกประเภทที่เพิ่มลงใน Bundle โดยอัตโนมัติ หากต้องการบันทึกสิ่งที่เพิ่มลงใน Bundle ไม่ได้ คุณมีตัวเลือกหลายอย่าง
Parcelize
วิธีที่ง่ายที่สุดคือการเพิ่มคำอธิบายประกอบ @Parcelize ลงในออบเจ็กต์ ออบเจ็กต์จะกลายเป็นพัสดุและรวมเป็นแพ็กเกจได้ ตัวอย่างเช่น โค้ดนี้จะสร้างประเภทข้อมูล City ที่แยกวิเคราะห์ได้และบันทึกลงในสถานะ
@Parcelize data class City(val name: String, val country: String) : Parcelable @Composable fun CityScreen() { var selectedCity = rememberSaveable { mutableStateOf(City("Madrid", "Spain")) } }
MapSaver
หาก @Parcelize ไม่เหมาะสมด้วยเหตุผลบางประการ คุณสามารถใช้ mapSaver เพื่อกำหนดกฎของคุณเองสำหรับการแปลงออบเจ็กต์เป็นชุดค่าที่ระบบสามารถบันทึกลงใน Bundle ได้
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() { var selectedCity = rememberSaveable(stateSaver = CitySaver) { mutableStateOf(City("Madrid", "Spain")) } }
ListSaver
หากไม่ต้องการกำหนดคีย์สำหรับแผนที่ คุณสามารถใช้ listSaver และใช้ดัชนีเป็นคีย์ได้ด้วย ดังนี้
data class City(val name: String, val country: String) val CitySaver = listSaver<City, Any>( save = { listOf(it.name, it.country) }, restore = { City(it[0] as String, it[1] as String) } ) @Composable fun CityScreen() { var selectedCity = rememberSaveable(stateSaver = CitySaver) { mutableStateOf(City("Madrid", "Spain")) } }
ตัวเก็บสถานะใน Compose
การย้ายสถานะแบบง่ายสามารถจัดการได้ในฟังก์ชันที่ประกอบกันได้เอง อย่างไรก็ตาม หากจำนวนสถานะที่ต้องติดตามเพิ่มขึ้น หรือตรรกะที่ต้องดำเนินการในฟังก์ชันที่ประกอบกันได้เกิดขึ้น แนวทางปฏิบัติแนะนำคือการมอบหมายความรับผิดชอบด้านตรรกะและสถานะให้กับคลาสอื่นๆ ซึ่งก็คือตัวเก็บสถานะ
โปรดทราบว่าในสื่ออื่นๆ ตัวเก็บสถานะจะเรียกว่าออบเจ็กต์สถานะที่ยกขึ้นด้วย
ดูข้อมูลเพิ่มเติมได้ที่เอกสารประกอบเกี่ยวกับการย้ายสถานะใน Compose หรือดูหน้าตัวเก็บสถานะและสถานะ UI ในคู่มือสถาปัตยกรรมเพื่อดูข้อมูลทั่วไปเพิ่มเติม
ทริกเกอร์การคำนวณการจดจำอีกครั้งเมื่อคีย์มีการเปลี่ยนแปลง
API remember มักใช้ร่วมกับ MutableState ดังนี้
var name by remember { mutableStateOf("") }
ในกรณีนี้ การใช้ฟังก์ชัน remember จะทำให้ค่า MutableState ยังคงอยู่แม้จะมีการจัดองค์ประกอบใหม่
โดยทั่วไป remember จะใช้พารามิเตอร์แลมบ์ดา calculation เมื่อเรียกใช้ remember เป็นครั้งแรก ระบบจะเรียกใช้ lambda calculation และจัดเก็บผลลัพธ์ไว้ ในระหว่างการจัดองค์ประกอบใหม่ remember จะแสดงผลค่าที่จัดเก็บไว้ล่าสุด
นอกจากการแคชสถานะแล้ว คุณยังใช้ remember เพื่อจัดเก็บออบเจ็กต์หรือผลลัพธ์ของการดำเนินการใน Composition ที่ต้องใช้ทรัพยากรมากในการเริ่มต้นหรือคำนวณได้ด้วย คุณอาจไม่ต้องการทำการคำนวณนี้ซ้ำในการจัดองค์ประกอบใหม่ทุกครั้ง
ตัวอย่างเช่น การสร้างออบเจ็กต์ ShaderBrush นี้ ซึ่งเป็นการดำเนินการที่มีค่าใช้จ่ายสูง
val brush = remember { ShaderBrush( BitmapShader( ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT ) ) }
remember จะจัดเก็บค่าไว้จนกว่าจะออกจาก Composition อย่างไรก็ตาม มีวิธีทำให้ค่าที่แคชไว้ใช้งานไม่ได้ remember API ยังใช้พารามิเตอร์ key หรือ keys ด้วย หากคีย์เหล่านี้มีการเปลี่ยนแปลง ครั้งถัดไปที่ฟังก์ชันจัดองค์ประกอบใหม่ remember จะทำให้แคชใช้งานไม่ได้และเรียกใช้บล็อกแลมบ์ดาการคำนวณอีกครั้ง กลไกนี้ช่วยให้คุณควบคุมอายุการใช้งานของออบเจ็กต์ใน Composition ได้ การคำนวณจะยังคงถูกต้องจนกว่าอินพุตจะเปลี่ยนแปลง แทนที่จะเป็นจนกว่าค่าที่จดจำไว้จะออกจาก Composition
ตัวอย่างต่อไปนี้แสดงวิธีการทำงานของกลไกนี้
ในข้อมูลโค้ดนี้ ระบบจะสร้าง ShaderBrush และใช้เป็นสีพื้นหลังของ Box Composable remember จะจัดเก็บอินสแตนซ์ ShaderBrush ไว้เนื่องจากมีค่าใช้จ่ายสูงในการสร้างใหม่ตามที่อธิบายไว้ก่อนหน้านี้ remember จะใช้ avatarRes เป็นพารามิเตอร์ key1 ซึ่งเป็นภาพพื้นหลังที่เลือก หาก avatarRes มีการเปลี่ยนแปลง แปรงจะจัดองค์ประกอบใหม่ด้วยรูปภาพใหม่ และนำไปใช้กับ Box อีกครั้ง กรณีนี้อาจเกิดขึ้นเมื่อผู้ใช้เลือกรูปภาพอื่นเป็นพื้นหลังจากเครื่องมือเลือก
@Composable private fun BackgroundBanner( @DrawableRes avatarRes: Int, modifier: Modifier = Modifier, res: Resources = LocalContext.current.resources ) { val brush = remember(key1 = avatarRes) { ShaderBrush( BitmapShader( ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT ) ) } Box( modifier = modifier.background(brush) ) { /* ... */ } }
ในข้อมูลโค้ดถัดไป สถานะจะถูกโฮสต์ไปยังคลาสตัวเก็บสถานะธรรมดา
MyAppState โดยจะแสดงฟังก์ชัน rememberMyAppState เพื่อเริ่มต้นอินสแตนซ์ของคลาสโดยใช้ remember การแสดงฟังก์ชันดังกล่าวเพื่อสร้างอินสแตนซ์ที่คงอยู่หลังจากการจัดองค์ประกอบใหม่เป็นรูปแบบที่พบได้ทั่วไปใน Compose ฟังก์ชัน rememberMyAppState จะได้รับ windowSizeClass ซึ่งทำหน้าที่เป็นพารามิเตอร์ key สำหรับ remember หากพารามิเตอร์นี้เปลี่ยนแปลง แอปจะต้องสร้างคลาสตัวเก็บสถานะธรรมดาขึ้นมาใหม่โดยใช้ค่าล่าสุด ซึ่งอาจเกิดขึ้นได้ เช่น เมื่อผู้ใช้หมุนอุปกรณ์
@Composable private fun rememberMyAppState( windowSizeClass: WindowSizeClass ): MyAppState { return remember(windowSizeClass) { MyAppState(windowSizeClass) } } @Stable class MyAppState( private val windowSizeClass: WindowSizeClass ) { /* ... */ }
Compose จะใช้การติดตั้งใช้งาน equals ของคลาสเพื่อตัดสินว่าคีย์มีการเปลี่ยนแปลงหรือไม่ และทำให้ค่าที่จัดเก็บไว้ใช้งานไม่ได้
จัดเก็บสถานะด้วยคีย์ที่นอกเหนือจากการจัดองค์ประกอบใหม่
API rememberSaveable เป็น Wrapper ของ remember ที่สามารถจัดเก็บข้อมูลใน Bundle API นี้ช่วยให้สถานะคงอยู่ได้ไม่เพียงแค่การจัดองค์ประกอบใหม่เท่านั้น แต่ยังรวมถึงการสร้างกิจกรรมใหม่และการสิ้นสุดการประมวลผลที่ระบบเริ่มต้นด้วย
rememberSaveable ได้รับพารามิเตอร์ input เพื่อวัตถุประสงค์เดียวกับที่ remember ได้รับ keys แคชจะใช้งานไม่ได้เมื่ออินพุตมีการเปลี่ยนแปลง ครั้งถัดไปที่ฟังก์ชันจัดองค์ประกอบใหม่ rememberSaveable จะเรียกใช้บล็อก Lambda การคำนวณอีกครั้ง
ในตัวอย่างต่อไปนี้ rememberSaveable จะจัดเก็บ userTypedQuery จนกว่า typedQuery จะเปลี่ยนแปลง
var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) { mutableStateOf( TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length)) ) }
ดูข้อมูลเพิ่มเติม
ดูข้อมูลเพิ่มเติมเกี่ยวกับสถานะและ Jetpack Compose ได้ที่แหล่งข้อมูลเพิ่มเติมต่อไปนี้
ตัวอย่าง
Codelab
วิดีโอ
บล็อก
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- การออกแบบสถาปัตยกรรม UI ของ Compose
- บันทึกสถานะ UI ใน Compose
- ผลข้างเคียงใน Compose