MutableState — สถานะที่สามารถสังเกตได้และกลไกการอัพเดตใน Compose

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-06-28 เวลาอ่าน: 7 นาที

MutableState คืออินเทอร์เฟสใน Jetpack Compose ที่แทนคอนเทนเนอร์สำหรับค่าที่สามารถเปลี่ยนแปลงและสังเกตได้ มันเป็นรากฐานของระบบตอบสนองของ Compose: ทุกครั้งที่ค่าของ MutableState เปลี่ยนแปลงผ่าน setter, Compose Runtime จะแจ้งไปยังส่วนประกอบที่อ่านทั้งหมดและเริ่มการประกอบใหม่ ตาม Google Android Developers, 2026 การเข้าใจ MutableState เป็นสิ่งจำเป็นสำหรับการทำงานอย่างถูกต้องกับสถานะใน UI แบบประกาศ

โดยเน้น

  • MutableState — อินเทอร์เฟส compose.runtime ที่มีหนึ่งคุณสมบัติ value (getter + setter)
  • State — อินเทอร์เฟสแม่แบบอ่านอย่างเดียว, MutableState เพิ่มความสามารถในการเขียน
  • การประกอบใหม่ ถูกเริ่มเมื่อเรียก setter ของ value ภายในวงจร snapshot ที่กำลังทำงาน
  • SnapshotMutationPolicy กำหนดเมื่อไรที่การเปลี่ยนแปลงถือว่ามีนัยสำหรับการประกอบใหม่
  • MutableIntState และที่คล้ายกัน — เวอร์ชันประถมภูมิที่ได้รับการปรับปรุงแล้วของ MutableState

MutableState ใน Jetpack Compose คืออะไร

MutableState คืออินเทอร์เฟสจากแพ็กเกจ androidx.compose.runtime ที่ประกาศคุณสมบัติเดียว: override var value: T getter จะส่งคืนค่าปัจจุบัน, setter จะเขียนค่าใหม่และแจ้ง Compose Runtime ถึงการเปลี่ยนแปลง อินเทอร์เฟสนี้สืบทอดจาก State<T>, โดยที่ value สามารถอ่านได้อย่างเดียว สถาปัตยกรรมสองระดับนี้ช่วยให้สามารถแยกการเข้าถึงได้: ส่วนประกอบที่ต้องการอ่านค่าอย่างเดียวจะได้รับ State<T>, ในขณะที่ส่วนประกอบเจ้าของจะได้รับ MutableState<T>

การนำไปใช้งานโดยแนะนำของ MutableState คือคลาสภายใน SnapshotMutableStateImpl, ซึ่งใช้กลไก snapshot ในการติดตามการเปลี่ยนแปลง เมื่อเรียก setter ของ value, snapshot ปัจจุบันจะบันทึกการเขียนและทำเครื่องหมาย ObservedScope ที่ลงทะเบียนไว้ทั้งหมดว่าไม่ถูกต้อง ขอบเขตเหล่านี้ (โดยทั่วไปคือฟังก์ชัน Composable) จะถูกประกอบใหม่ในเฟรมถัดไป กระบวนการทั้งหมดเกิดขึ้นแบบซิงค์โครนัสและไม่มีการล็อคด้วยสถาปัตยกรรม Lock-free snapshot

State vs MutableState: State คืออินเทอร์เฟสสำหรับการอ่านอย่างเดียวที่ใช้สำหรับ API สาธารณะของส่วนประกอบ เมื่อคุณประกาศพารามิเตอร์ฟังก์ชัน Composable เป็น State<Int>, คุณรับประกันว่าส่วนประกอบสามารถอ่านได้แต่ไม่สามารถเปลี่ยนสถานะได้ MutableState ถูกใช้ภายในส่วนประกอบเจ้าของ การแยกแยะนี้เป็นหนึ่งในแนวปฏิบัติพื้นฐานของ Compose ที่ป้องกันการเปลี่ยนแปลงโดยไม่ได้รับอนุญาต

ลำดับชั้นของ State, MutableState และอินเทอร์เฟสที่สืบทอด

ลำดับชั้นของอินเทอร์เฟสสถานะใน Compose มีหลายระดับ อยู่โดดยอนุกรมคือ State<T> ที่มี value แบบอ่านอย่างเดียว ถัดลงไปคือ MutableState<T> ที่มี value แบบอ่าน-เขียน ถัดลงไปอีกเป็นเวอร์ชันประถมภูมิเฉพาะทาง: MutableIntState, MutableFloatState, MutableLongState, MutableBooleanState และอื่นๆ, ซึ่งหลีกเลี่ยงการห่อหิบ (บ็อกซิ่ง) ของประถมภูมิ

MutableDoubleState และ MutableLongState ไม่ทั่วไปแต่ก็มีอยู่ อินเทอร์เฟสคอลเล็กชัน: MutableListState — สำหรับติดตามการเปลี่ยนแปลงภายในรายการ, MutableStateMap — สำหรับแมพ แต่ละอินเทอร์เฟสเหล่านี้ได้รับการปรับปรุงสำหรับสถานการณ์เฉพาะและขยาย MutableState พื้นฐานด้วยวิธีการจัดการคอลเล็กชันเพิ่มเติม

SnapshotStateList และ SnapshotStateMap เป็นการนำไปใช้ของรายการและแมพที่สามารถเปลี่ยนแปลงได้ซึ่งเข้ากันได้กับ snapshot พวกมันสามารถติดตามไม่เพียงการแทนที่ค่า แต่รวมถึงการเปลี่ยนแปลงภายใน: การเพิ่มรายการในรายการ, การลบ, การแก้ไขรายการที่มีอยู่ สำหรับโครงสร้างเช่นนี้, mutableStateListOf() และ mutableStateMapOf() จะสร้างคอลเล็กชันที่สามารถสังเกตได้ตามลำดับ

อินเทอร์เฟสวัตถุประสงค์วิธีการสร้าง
State<T>คอนเทนเนอร์แบบอ่านอย่างเดียว
MutableState<T>คอนเทนเนอร์แบบอ่าน-เขียนmutableStateOf()
MutableIntStateInt ประถมภูมิโดยไม่มีการห่อหิบmutableIntStateOf()
MutableFloatStateFloat ประถมภูมิโดยไม่มีการห่อหิบmutableFloatStateOf()
SnapshotStateListรายการที่สามารถสังเกตได้mutableStateListOf()
SnapshotStateMapแมพที่สามารถสังเกตได้mutableStateMapOf()

SnapshotMutationPolicy: เมื่อไรที่จะเริ่มการประกอบใหม่

SnapshotMutationPolicy คืออินเทอร์เฟสที่กำหนดเมื่อไรที่การเปลี่ยนแปลงใน MutableState ถือว่ามีนัยสำคัณ mutableStateOf รับ policy เป็นอาร์กิวเมนต์ที่สอง การนำไปใช้มาตรฐาน: structuralEquality() (equals), referentialEquality() (===), neverEqualPolicy() (ถือว่าการเปลี่ยนแปลงทุกครั้งมีนัยสำคัณ) สามารถดำเนินการกำหนดนโยบายเองสำหรับตรรระกะอที่กำหนดเอง

structuralEquality() — พฤติกรรมเริ่มต้น Compose เปรียบเทียบค่าใหม่กับค่าเก่าโดยใช้ equals() หากผลลัพธ์เป็น true, จะไม่มีการประกอบใหม่ สะดวกสำหรับประถมภูมิและ data class, ซึ่งสองอินสแตนซ์ที่มีฟิลด์เดียวกันจะถือว่าเท่ากัน ปัญหา: หาก data class มี List, equals() จะทำการเปรียบเทียบแบบลึก, ซึ่งอาจมีค่าใช้จ่ายสำหรับรายการขนาดใหญ่

referentialEquality() — เปรียบเทียบการอ้างอิงโดยใช้ === การประกอบใหม่จะเกิดขึ้นเมื่อมีการกำหนดอ็อบเจกต์ที่แตกต่างกัน, แม้ว่าเนื้อหาจะเหมือนกัน ที่เหมาะสำหรับ data class ที่ไม่สามารถเปลี่ยนแปลงได้ โดยที่แต่ละอินสแตนซ์ใหม่รับประกันว่าเป็นการเปลี่ยนแปลง neverEqualPolicy() — ถือว่าการเปลี่ยนแปลงทุกครั้งมีนัยสำคัณโดยไม่ต้องเปรียบเทียบ มีประโยชน์เมื่อ setter ถูกเรียกไม่บ่อยและไม่จำเป็นต้องเสียเวลากับ equals

kotlin
    // Policy comparison in practice
data class User(val name: String, val age: Int)

@Composable
fun UserProfile() {
    // structuralEquality: recomposition ONLY if data changed
    var user1 by remember {
        mutableStateOf(User("Alice", 30))
    }

    // referentialEquality: recomposition on ANY assignment
    var user2 by remember {
        mutableStateOf(User("Bob", 25),
            SnapshotMutationPolicy.referentialEquality())
    }

    // user1: copy() with same fields does NOT trigger recomposition
    // user2: even user2.copy() == user2 triggers recomposition (new ref)
}

State เบื้องต้น: MutableIntState, MutableFloatState, MutableLongState

MutableIntState และที่คล้ายกันเป็นอินเทอร์เฟสเฉพาะทางที่จัดเก็บประถมภูมิโดยไม่มีการห่อหิบ MutableState<Int> ทั่วไปจัดเก็บ Int เป็น Integer, ซึ่งสร้างอ็อบเจกต์บนฮีปทุกครั้งที่เขียน MutableIntState จัดเก็บ int (ประถมภูมิ), ซึ่งช่วยลดโอเวอร์เฮดของการห่อหิบได้อย่างสมบูรณ์ นี้มีความสำคัญเฉพาะสำหรับการอัพเดตความถี่สูง — ตัวนับ, ตำแหน่งการเลื่อนไผล, ค่าแอนิเมชั่น

mutableIntStateOf(), mutableFloatStateOf(), mutableLongStateOf() — ฟังก์ชันที่สร้าง MutableState แบบประถมภูมิ อินเทอร์เฟสเหล่านี้เรียกว่า MutableIntState, MutableFloatState, MutableLongState พวกมันขยาย MutableState<Int>, MutableState<Float> และ MutableState<Long> ตามลำดับ, และเพิ่มคุณสมบัติ intValue สำหรับการเข้าถึงประถมภูมิอย่างรวดเร็ว การนำไปใช้ภายในใช้ AtomicInteger สำหรับการอ่าน/เขียนที่ไม่มีการล็อค

การใช้งาน: ตัวนับ (Int), ตำแหน่งการเลื่อนไผล (Float offset), เวลาประทับ (Long) ในสถานการณ์ส่วนใหญ่ในชีวิตประจำวัน, ความแตกต่างด้านประสิทธิภาพไม่สามารถรับรู้ได้ แต่ใน LazyList ที่มีรายการพันรายการและแอนิเมชั่นเพื่อรับการเปลี่ยนแปลง, State แบบประถมภูมิจะให้การปรับปรุงที่เหน็ได้ชัดเจน Google แนะนำให้ใช้ State แบบประถมภูมิสำหรับสถานการณ์ทั่วไปแทนที่จะใช้ mutableStateOf ที่เป็นสากลสากล

kotlin
@Composable
fun ScrollCounter() {
    // Bad: boxing on every update
    var badCount by remember { mutableStateOf(0) }

    // Good: no boxing, primitive storage
    var goodCount by remember { mutableIntStateOf(0) }

    // Usage is identical
    Button(onClick = { goodCount++ }) {
        Text("Count: $goodCount")
    }
}

ตัวอย่างการใช้งาน MutableState

ลองพิจารณาส่วนประกอบ TodoList, ซึ่งใช้ MutableState ในสองรูปแบบ: เป็นตัวแปรแยกต่างๆ สำหรับสถานะอินพุต และเป็น SnapshotStateList สำหรับรายการงานแบบไดนามิก ทั้งสองใช้การมอบหมายเพื่อความกระชับของโค้ด

kotlin
data class TodoItem(val id: Int, val text: String, val isDone: Boolean = false)

@Composable
fun TodoScreen() {
    var inputText by remember { mutableStateOf("") }
    val items = remember { mutableStateListOf() }

    Column(modifier = Modifier.padding(16.dp)) {
        Row {
            TextField(
                value = inputText,
                onValueChange = { inputText = it }
            )
            Button(onClick = {
                if (inputText.isNotBlank()) {
                    items.add(TodoItem(items.size, inputText))
                    inputText = ""
                }
            }) { Text("Add") }
        }

        LazyColumn {
            items(items) { item ->
                Row(modifier = Modifier.fillMaxWidth().clickable {
                    val idx = items.indexOf(item)
                    items[idx] = item.copy(isDone = !item.isDone)
                }) {
                    Checkbox(checked = item.isDone, onCheckedChange = null)
                    Text(item.text)
                }
            }
        }
    }
}

mutableStateListOf สร้าง SnapshotStateList — รายการที่สามารถเปลี่ยนแปลงได้ซึ่งติดตามการเปลี่ยนแปลงของแต่ละรายการ เมื่อ items.add() และ items[n] = newValue ถูกเรียก, Compose จะเห็นการเปลี่ยนแปลงและประกอบใหม่เฉพาะส่วนของ LazyColumn ที่เปลี่ยนแปลง inputText เป็น MutableState<String> ทั่วไป การรวมกันของ MutableState สองประเภท (เดียวและคอลเล็กชัน) เป็นรูปแบบทั่วไปสำหรับหน้าจอที่มีฟอร์มและรายการ

คำถามที่พบบ่อย

ฉันสามารถใช้ MutableState โดยไม่มี remember ได้หรือไม่?

MutableState ที่ไม่มี remember จะถูกสร้างใหม่ทุกครั้งที่มีการประกอบใหม่ ทุกครั้งที่เรียก mutableStateOf ใหม่จะสร้างอ็อบเจกต์ใหม่และค่าเก่าจะหายไป ใช้ remember เสมอเพื่อเก็บ State ไว้ระหว่างการประกอบใหม่, เว้นแต่จะ State ถูกสร้างภายนอก Composable (เช่นใน ViewModel)

จะแปลง MutableState เป็นตัวแปรทั่วไปได้อย่างไร?

ลองอ่าน .value หนึ่งครั้งนอก snapshot ผ่าน snapshot { } แต่ทำให้การตอบสนองหยุดทำงาน — การเปลี่ยนแปลงจะไม่ทำให้เกิดการประกอบใหม่อีก สำหรับการอ่านครั้งเดี่ยวโดยไม่ต้องสมัครสมาชิก, ใช้ currentValue() ภายใน snapshot โดยไม่ต้องอ่าน

อะไรเร็วกว่า: mutableStateOf หรือ mutableIntStateOf?

mutableIntStateOf เร็วกว่าเพราะไม่ต้องห่อ int เป็น Integer ด้วยการอัพเดตหลายพันครั้งต่อวินาที (แอนิเมชั่น, การเลื่อนไผล) ความแตกต่างอาจถึง 30-50% ของเวลาการจัดสรรค์ สำหรับการอัพเดตที่ไม่บ่อย (คลิก, การป้อนข้อความ), ความแตกต่างไม่มีนัยสำคัณ

สามารถใช้ MutableState เป็นอาร์กิวเมนต์ของฟังก์ชัน Composable ได้หรือไม่?

ได้แต่ไม่แนะนำ แทนที่จะใช้ MutableState, ให้ส่ง State (อ่านอย่างเดียว) + lambda onValueChange สิ่งนี้จะดำเนินการตามรูปแบบ State Hoisting และทำให้ส่วนประกอบสามารถนำกลับมาใช้ใหม่ได้ ส่วนประกอบที่ยอมรับ MutableState จะละเมิดการไหลข้อมูลทางเดียว

จะสร้าง MutableState แบบกำหนดเองได้อย่างไร?

นำไปใช้อินเทอร์เฟส MutableState และเพิ่ม override var value ด้วย getter และ setter ใน setter คุณสามารถเพิ่มการตรวจสอบหรือการบันทึกได้ สำหรับความเข้ากันได้กับ Compose Runtime, ห่อการนำไปใช้ที่กำหนดเองของคุณใน snapshotFlow หรือใช้ snapshotIncrement

สรุป

  • MutableState — อินเทอร์เฟสพื้นฐานสำหรับสถานะที่สามารถเปลี่ยนแปลงและสังเกตได้ใน Compose
  • State — เวอร์ชันสำหรับการอ่านอย่างเดียวสำหรับการส่งข้อมูลโดยไม่มีสิทธิ์ในการแก้ไข
  • SnapshotMutationPolicy จัดการเงื่อนไขสำหรับการเริ่มต้นการประกอบใหม่เมื่อมีการเปลี่ยนแปลง
  • State แบบประถมภูมิ (MutableIntState และอื่นๆ) กำจัดโอเวอร์เฮดของการห่อหิบ
  • SnapshotStateList และ SnapshotStateMap ติดตามการเปลี่ยนแปลงภายในของคอลเล็กชัน
  • การประกอบใหม่ เริ่มต้นโดยอัตโนมัติเมื่อมีการเรียก setter ของ value
  • คำแนะนำ: ใช้ MutableState สำหรับการเป็นเจ้าของสถานะและ State สำหรับการส่งต่อไปยังส่วนล่าง

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม