remember เป็นฟังก์ชันใน Jetpack Compose ที่ช่วยให้คุณเก็บค่าระหว่างการประกอบใหม่ ป้องกันการรีเซ็ตสถานะเมื่อเริ่มต้นฟังก์ชัน Composable แต่ละครั้ง หากไม่มี remember ตัวแปรทั้งหมดที่ประกาศภายในฟังก์ชันจะถูกรีเซ็ตทุกครั้งที่ UI อัปเดต ทำให้สถานะไม่เสถียรและไร้ประโยชน์ ตามข้อมูลจาก Google Android Developers, 2026 การใช้ remember อย่างถูกต้องเป็นพื้นฐานของการจัดการสถานะที่ถูกต้องใน UI เชิงประกาศ
ประเด็นสำคัญ
remember เป็นฟังก์ชันในตัวของ Jetpack Compose จากแพ็คเกจ androidx.compose.runtime ที่สร้างออบเจ็กต์ที่เก็บค่าระหว่างการเรียกฟังก์ชัน Composable อย่างต่อเนื่อง ในทางเทคนิค remember ทำงานกับสล็อต — เซลล์หน่วยความจำพิเศษที่จัดสรรสำหรับแต่ละตำแหน่งการเรียกฟังก์ชันในโครงสร้าง UI ตราบใดที่ฟังก์ชันยังคงอยู่ในการประกอบ (ไม่ได้ถูกลบออกผ่านเงื่อนไข if) remember จะส่งคืนค่าที่บันทึกไว้ในการประกอบใหม่แต่ละครั้ง
ไวยากรณ์ของ remember นั้นง่าย: ภายในวงเล็บปีกกาจะระบุบล็อกการคำนวณค่าเริ่มต้น บล็อกจะถูกดำเนินการเพียงครั้งเดียว — ระหว่างการประกอบครั้งแรกของฟังก์ชัน การประกอบใหม่ที่ตามมาทั้งหมดจะส่งคืนค่าที่บันทึกไว้แล้วโดยไม่ดำเนินการบล็อกอีกครั้ง อย่างไรก็ตาม หากมีการระบุพารามิเตอร์คีย์ บล็อกจะถูกดำเนินการอีกครั้งเมื่อคีย์เปลี่ยนแปลง ทำให้สามารถคำนวณค่าใหม่ตามข้อมูลอินพุตได้
remember ไม่ใช่เวทมนตร์ของ Kotlin — เป็นฟังก์ชันธรรมดาที่มีพารามิเตอร์คีย์และแลมบ์ดาการคำนวณ การทำงานภายในใช้ Composer สำหรับอ่านและเขียนในสล็อต คอมไพเลอร์ Kotlin เมื่อเห็นการเรียก remember จะสร้างโค้ดที่เข้าถึง CompositionContext ปัจจุบันและจัดการสล็อต ซึ่งหมายความว่า remember สามารถเรียกได้เฉพาะภายในฟังก์ชัน Composable หรือฟังก์ชันอื่นในบริบทของการประกอบเท่านั้น
ใน Jetpack Compose มีสามรูปแบบหลักของ remember แต่ละรูปแบบมีวัตถุประสงค์ของตนเอง remember พื้นฐานเก็บค่าเฉพาะในหน่วยความจำของกระบวนการปัจจุบัน — เมื่อหมุนหน้าจอ (การเปลี่ยนการกำหนดค่า) Compose จะสร้าง Composition ใหม่และค่า remember ทั้งหมดจะถูกรีเซ็ต เพื่อเก็บข้อมูลระหว่างการเปลี่ยนแปลงการกำหนดค่าและการหยุดกระบวนการ จะใช้ rememberSaveable
rememberSaveable ทำให้ค่าเป็นอนุกรมใน Bundle ผ่านกลไก SavedStateHandle หรือ Parcelable ซึ่งช่วยให้อยู่รอดจากการหมุนหน้าจอ การตั้งค่า "ไม่เก็บกิจกรรม" และแม้แต่การย่อขนาดแอปชั่วคราว อย่างไรก็ตาม rememberSaveable มีข้อจำกัดเกี่ยวกับชนิดของข้อมูลที่สามารถจัดเก็บได้: ต้องเป็นชนิดพื้นฐาน Parcelable, Serializable หรือรองรับตัวแปลง Saver
derivedStateOf ไม่ใช่กลไกการเก็บรักษา แต่เป็นการเพิ่มประสิทธิภาพ มันสร้าง State ที่มีค่าคำนวณจากออบเจ็กต์ State อื่น ๆ derivedStateOf ตอบสนองต่อการเปลี่ยนแปลงของสถานะต้นทาง แต่คำนวณค่าใหม่เฉพาะเมื่อมีสมาชิกเท่านั้น หากการประกอบใหม่ปัจจุบันไม่อ่าน derivedStateOf การคำนวณจะไม่เกิดขึ้น ช่วยประหยัดทรัพยากรในการอัปเดตที่บ่อยครั้งแต่ไม่จำเป็น
@Composable
fun RememberVariants() {
// 1. Remember พื้นฐาน: คงอยู่จนกว่าจะออกจากการประกอบ
val createdAt = remember { System.currentTimeMillis() }
// 2. rememberSaveable: อยู่รอดเมื่อหมุนหน้าจอ
var username by rememberSaveable { mutableStateOf("") }
// 3. derivedStateOf: คำนวณเมื่อจำเป็นเท่านั้น
val isButtonVisible = remember {
derivedStateOf { username.length() > 3 }
}
Text("สร้างเมื่อ: $createdAt")
TextField(value = username, onValueChange = { username = it })
if (isButtonVisible.value) {
Text("ปุ่มจะถูกแสดง")
}
}
การเลือกระหว่าง remember และ rememberSaveable ขึ้นอยู่กับว่าการเก็บข้อมูลระหว่างการเปลี่ยนแปลงการกำหนดค่ามีความสำคัญเพียงใด สำหรับสถานะชั่วคราวที่ไม่สำคัญหากสูญเสียเมื่อหมุน (แอนิเมชัน ตำแหน่งเลื่อนปัจจุบัน สถานะโฟกัส) — remember ปกติก็เพียงพอ สำหรับข้อมูลสำคัญ (ข้อความในฟอร์ม รายการที่เลือก กล่องกาเครื่องหมาย) — ให้ใช้ rememberSaveable
ประสิทธิภาพ ของ rememberSaveable ต่ำกว่า remember ปกติเนื่องจากต้องทำให้เป็นอนุกรมในBundle ใช้ rememberSaveable เฉพาะสำหรับข้อมูลที่ต้องอยู่รอดจากการสร้าง Activity ใหม่จริงๆ สำหรับทุกสิ่งอื่น — ใช้ remember ธรรมดา การใช้ rememberSaveable มากเกินไปทำให้เกิดความช้าเมื่อหมุนหน้าจอและเมื่อสลับระหว่างแอป
หากคุณทำงานกับคลาสที่ไม่รองรับ Parcelable หรือ Serializable ให้ใช้ Saver — ตัวแปลงที่กำหนดวิธีการบันทึกและกู้คืนออบเจ็กต์ Saver อธิบายด้วยคู่ของแลมบ์ดา: save (แปลงออบเจ็กต์เป็นชนิดที่จัดเก็บได้) และ restore (กู้คืนออบเจ็กต์จากข้อมูลที่บันทึกไว้) Saver มาตรฐานได้ถูกนำไปใช้แล้วสำหรับ mutableStateListOf และ mutableStateMapOf
| คุณลักษณะ | remember | rememberSaveable |
|---|---|---|
| การเก็บรักษาระหว่างการประกอบใหม่ | ใช่ | ใช่ |
| การเก็บรักษาเมื่อหมุน | ไม่ | ใช่ |
| การเก็บรักษาเมื่อหยุดกระบวนการ | ไม่ | ใช่ |
| ข้อกำหนดชนิด | ใดก็ได้ | Parcelable, Serializable, Saver |
| ประสิทธิภาพ | สูง | ปานกลาง |
พิจารณาสถานการณ์ทั่วไป — หน้าจอแก้ไขโปรไฟล์ที่ใช้ remember สำหรับหลายวัตถุประสงค์: การเก็บสถานะของฟิลด์ฟอร์ม การคำนวณค่าที่ได้รับมา และการแคชการดำเนินการที่ใช้ทรัพยากรในการคำนวณสูง
data class ProfileUiState(
val name: String = "",
val bio: String = "",
val isSaving: Boolean = false
)
@Composable
fun ProfileEditor() {
var state by rememberSaveable { mutableStateOf(ProfileUiState()) }
val isValid = remember {
derivedStateOf { state.name.isNotBlank() && state.bio.length() <= 500 }
}
val bioWarning = remember(state.bio) {
if (state.bio.length() > 400) {
"${500 - state.bio.length} chars left"
} else null
}
Column(modifier = Modifier.padding(16.dp)) {
OutlinedTextField(
value = state.name,
onValueChange = { state = state.copy(name = it) },
label = { Text("ชื่อ") }
)
OutlinedTextField(
value = state.bio,
onValueChange = { state = state.copy(bio = it) },
label = { Text("เกี่ยวกับ") }
)
bioWarning?.let { Text(it, color = MaterialTheme.colorScheme.error) }
Button(onClick = { /* save */ },
enabled = isValid.value) {
Text("บันทึก")
}
}
}
ในตัวอย่าง สถานะถูกบันทึกผ่าน rememberSaveable — ข้อความจะไม่สูญหายเมื่อหมุนหน้าจอ isValid ถูกคำนวณผ่าน derivedStateOf ซึ่งป้องกันการคำนวณที่ไม่จำเป็นระหว่างการประกอบใหม่ bioWarning ใช้ remember ที่มีคีย์ bio — นี่คือการคำนวณที่ใช้ทรัพยากรสูง (เป็นตัวเลือก สำหรับการสาธิต) ซึ่งจะคำนวณใหม่เฉพาะเมื่อ bio เปลี่ยนแปลง ไม่ใช่ทุกการประกอบใหม่
สถานะที่ได้รับมาคือค่าที่คำนวณจากออบเจ็กต์ State อื่นๆ แทนที่จะคำนวณทุกการประกอบใหม่และทำให้ CPU สิ้นเปลืองกับผลลัพธ์ที่เหมือนกัน remember กับ derivedStateOf จะคำนวณค่าเฉพาะเมื่อแหล่งที่มาเปลี่ยนแปลงเท่านั้น ซึ่งมีประโยชน์อย่างยิ่งสำหรับการกรอง การเรียงลำดับ และการรวมข้อมูล
remember ที่มีคีย์ (remember(key) { calculation }) เป็นกลไกการเพิ่มประสิทธิภาพอีกแบบหนึ่ง หากคีย์ไม่เปลี่ยนแปลงตั้งแต่การประกอบใหม่ครั้งล่าสุด บล็อกการคำนวณจะไม่ถูกดำเนินการและส่งคืนค่าที่แคชไว้ ซึ่งสะดวกสำหรับการแคชออบเจ็กต์ที่สร้างได้ยาก: การจัดรูปแบบวันที่ การแยกวิเคราะห์ JSON การสร้างคอลเล็กชันที่ไม่เปลี่ยนแปลงขนาดใหญ่
@Composable
fun SearchResults(allItems: List<Item>, query: String) {
// derivedStateOf: ตัวกรองคำนวณใหม่เมื่ออินพุตเปลี่ยนแปลงเท่านั้น
val filtered = remember {
derivedStateOf {
allItems.filter { it.title.contains(query, true) }
}
}
// remember ที่มีคีย์: สถิติที่จัดรูปแบบคำนวณใหม่เมื่อคิวรีเปลี่ยนแปลงเท่านั้น
val statsText = remember(query) {
"Results for query \"$query\": ${filtered.value.size}"
}
Text(statsText)
LazyColumn {
items(filtered.value, key = { it.id }) { item ->
Text(item.title)
}
}
}
filtered เป็น derivedStateOf ที่คำนวณใหม่โดยอัตโนมัติเมื่อ allItems หรือ query เปลี่ยนแปลง statsText ใช้ remember(query) — การจัดรูปแบบสตริงที่ใช้ทรัพยากรสูงจะดำเนินการเฉพาะเมื่อคำค้นหาเปลี่ยนแปลงเท่านั้น การรวมกันของ derivedStateOf และ remember ที่มีคีย์ให้ประสิทธิภาพสูงสุด: สถานะที่ได้รับมาจะถูกคำนวณเมื่อจำเป็นเท่านั้น และออบเจ็กต์ที่ซับซ้อนจะถูกแคชไว้จนกว่าคีย์จะเปลี่ยนแปลง
คำถามที่พบบ่อย
ไม่ remember เป็นฟังก์ชันจากแพ็คเกจ compose.runtime ที่ต้องการ CompositionContext สามารถเรียกได้เฉพาะภายในฟังก์ชัน @Composable หรือภายในฟังก์ชันอื่นที่เรียกจาก Composable เท่านั้น หากต้องการเก็บข้อมูลนอกการประกอบ ให้ใช้ ViewModel
หากไม่มีคีย์ remember จะดำเนินการบล็อกการคำนวณเพียงครั้งเดียว — ระหว่างการประกอบครั้งแรก การประกอบใหม่ที่ตามมาทั้งหมดจะส่งคืนค่าที่บันทึกไว้ หากคุณต้องการคำนวณค่าใหม่เมื่อข้อมูลเปลี่ยนแปลง โปรดระบุเป็นคีย์: remember(data) { compute(data) }
ไม่มีวิธีโดยตรงในการรีเซ็ต remember วิธีเดียวคือนำฟังก์ชันออกจากการประกอบ (เช่น ซ่อนด้วยเงื่อนไข if) แล้วแสดงอีกครั้ง เมื่อเข้าสู่ครั้งถัดไป บล็อก remember จะถูกดำเนินการอีกครั้ง สร้างค่าเริ่มต้นใหม่
remember จัดเก็บสถานะในสล็อตของฟังก์ชัน Composable และคงอยู่ตราบเท่าที่ฟังก์ชันยังอยู่ในการประกอบ ViewModel คงอยู่ตราบเท่าที่วงจรชีวิตของหน้าจอยังคงอยู่ ViewModel จะถูกเก็บรักษาเมื่อหมุนและใช้สำหรับตรรกะทางธุรกิจ remember มีไว้สำหรับสถานะ UI เฉพาะที่ที่ไม่จำเป็นนอกฟังก์ชันเดียว
ใช่ remember ทำงานอย่างถูกต้องในฟังก์ชัน @Preview Composable เนื่องจาก Preview สร้าง CompositionContext ที่สมบูรณ์ อย่างไรก็ตาม rememberSaveable อาจทำงานไม่ถูกต้องใน Preview เนื่องจาก SavedStateHandle อาจไม่มีอยู่ในสภาพแวดล้อมการแสดงตัวอย่าง
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม