State และ Jetpack Compose

สถานะในแอปคือค่าใดก็ได้ที่เปลี่ยนแปลงได้เมื่อเวลาผ่านไป คำจำกัดความนี้กว้างมากและครอบคลุมตั้งแต่ฐานข้อมูล Room ไปจนถึงตัวแปรในคลาส

แอป Android ทั้งหมดจะแสดงสถานะต่อผู้ใช้ ตัวอย่างสถานะใน Android App

  • แถบแสดงข้อความที่แสดงเมื่อไม่สามารถเชื่อมต่อเครือข่ายได้
  • บล็อกโพสต์และความคิดเห็นที่เกี่ยวข้อง
  • ภาพเคลื่อนไหวระลอกคลื่นบนปุ่มที่เล่นเมื่อผู้ใช้คลิก
  • สติกเกอร์ที่ผู้ใช้วาดทับรูปภาพได้

Jetpack Compose ช่วยให้คุณระบุตำแหน่งและวิธีจัดเก็บและใช้สถานะในแอป Android ได้อย่างชัดเจน คู่มือนี้มุ่งเน้นที่การเชื่อมต่อระหว่างสถานะกับคอมโพสิเบิล และ API ที่ Jetpack Compose มีให้เพื่อทำงานกับสถานะได้ง่ายขึ้น

สถานะและองค์ประกอบ

คอมโพสิชันเป็นแบบประกาศ ดังนั้นวิธีเดียวที่จะอัปเดตได้คือการเรียกใช้คอมโพสิชันเดียวกันด้วยอาร์กิวเมนต์ใหม่ โดยอาร์กิวเมนต์เหล่านี้แสดงสถานะของ UI ทุกครั้งที่มีการอัปเดตสถานะ ระบบจะจัดองค์ประกอบใหม่ ด้วยเหตุนี้ รายการต่างๆ เช่น TextField จึงจะไม่อัปเดตโดยอัตโนมัติเหมือนในมุมมองแบบบังคับซึ่งอิงตาม XML 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 เปลี่ยนแปลง ปัญหานี้เกิดจากวิธีการทำงานของการจัดองค์ประกอบและการจัดองค์ประกอบใหม่ใน Compose

ดูข้อมูลเพิ่มเติมเกี่ยวกับการจัดองค์ประกอบเริ่มต้นและการจัดองค์ประกอบใหม่ได้ที่การคิดเชิงเขียน

สถานะในคอมโพสิเบิล

ฟังก์ชันที่ประกอบกันได้จะใช้ API remember เพื่อจัดเก็บออบเจ็กต์ในหน่วยความจำ ระบบจะจัดเก็บค่าที่คำนวณโดย remember ไว้ในองค์ประกอบระหว่างการจัดองค์ประกอบครั้งแรก และจะแสดงผลค่าที่เก็บไว้ระหว่างการจัดองค์ประกอบอีกครั้ง remember ใช้จัดเก็บทั้งออบเจ็กต์ที่เปลี่ยนแปลงได้และเปลี่ยนแปลงไม่ได้

mutableStateOf สร้าง Observable MutableState<T> ซึ่งเป็นประเภท Observable ที่ผสานรวมกับรันไทม์ของ Compose

interface MutableState<T> : State<T> {
    override var value: T
}

การเปลี่ยนแปลงใดๆ ในการจัดตารางเวลาของ value การจัดองค์ประกอบฟังก์ชันที่ประกอบกันได้ซึ่งอ่าน value ใหม่

การประกาศออบเจ็กต์ MutableState ในคอมโพสิเบิลทำได้ 3 วิธีดังนี้

  • val mutableState = remember { mutableStateOf(default) }
  • var value by remember { mutableStateOf(default) }
  • val (value, setValue) = remember { mutableStateOf(default) }

การประกาศเหล่านี้เทียบเท่ากันและจัดเตรียมไว้เป็นไวยากรณ์ทางเลือกสำหรับการใช้สถานะที่แตกต่างกัน คุณควรเลือกรูปแบบที่ผลิตโค้ดที่อ่านง่ายที่สุดในคอมโพสิเบิลที่คุณเขียน

ไวยากรณ์การมอบสิทธิ์ by ต้องมีการนําเข้าต่อไปนี้

import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue

คุณสามารถใช้ค่าที่บันทึกไว้เป็นพารามิเตอร์สําหรับคอมโพสิเบิลอื่นๆ หรือแม้แต่เป็นตรรกะในคำสั่งเพื่อเปลี่ยนคอมโพสิเบิลที่จะแสดง ตัวอย่างเช่น หากไม่ต้องการให้แสดงคําทักทายหากชื่อว่างเปล่า ให้ใช้สถานะใน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 โดยอัตโนมัติ สําหรับค่าอื่นๆ คุณสามารถส่งออบเจ็กต์โปรแกรมช่วยบันทึกที่กําหนดเองได้

แทนการใช้ออบเจ็กต์ที่เปลี่ยนแปลงได้แต่ไม่สามารถสังเกตได้

สถานะประเภทอื่นๆ ที่รองรับ

คุณไม่จำเป็นต้องใช้ MutableState<T> เพื่อเขียนคำสั่งในการระงับสถานะ แต่รองรับประเภทอื่นๆ ที่สังเกตได้ ก่อนอ่านประเภทที่สังเกตได้อื่นใน Compose คุณต้องแปลงเป็น State<T> เพื่อให้คอมโพสิเบิลคอมไพล์ใหม่โดยอัตโนมัติเมื่อสถานะมีการเปลี่ยนแปลง

คอมโพสิชันเรือกับฟังก์ชันเพื่อสร้าง State<T> จากประเภทที่สังเกตได้ทั่วไปซึ่งใช้ในแอป Android ก่อนใช้การผสานรวมเหล่านี้ ให้เพิ่มอาร์ติแฟกต์ที่เหมาะสมตามที่ระบุไว้ด้านล่าง

  • Flow: collectAsStateWithLifecycle()

    collectAsStateWithLifecycle() จะรวบรวมค่าจาก Flow ในลักษณะที่คำนึงถึงวงจร ทำให้แอปของคุณประหยัดทรัพยากรได้ ค่านี้แสดงค่าที่ส่งออกล่าสุดจาก State ของคอมโพสิชัน ใช้ API นี้เป็นวิธีที่แนะนําในการรวบรวมการไหลเวียนในแอป Android

    ต้องมีข้อกําหนดเบื้องต้นต่อไปนี้ในไฟล์ build.gradle (ควรเป็น 2.6.0-beta01 ขึ้นไป)

KotlinGroovy
dependencies {
      ...
      implementation("androidx.lifecycle:lifecycle-runtime-compose:2.8.7")
}
dependencies {
      ...
      implementation "androidx.lifecycle:lifecycle-runtime-compose:2.8.7"
}
  • Flow: collectAsState()

    collectAsState คล้ายกับ collectAsStateWithLifecycle เนื่องจากจะรวบรวมค่าจาก Flow และเปลี่ยนค่าดังกล่าวเป็น Compose State ด้วย

    ใช้ collectAsState สำหรับโค้ดที่ไม่ขึ้นอยู่กับแพลตฟอร์มแทน collectAsStateWithLifecycle ซึ่งใช้ได้กับ Android เท่านั้น

    collectAsState ไม่จำเป็นต้องใช้ทรัพยากรเพิ่มเติมเนื่องจากมีให้บริการใน compose-runtime

  • LiveData: observeAsState()

    observeAsState() เริ่มสังเกต LiveData นี้และแสดงค่าผ่าน State

    ต้องระบุ dependency ต่อไปนี้ในไฟล์ build.gradle

KotlinGroovy
dependencies {
      ...
      implementation("androidx.compose.runtime:runtime-livedata:1.7.8")
}
dependencies {
      ...
      implementation "androidx.compose.runtime:runtime-livedata:1.7.8"
}
KotlinGroovy
dependencies {
      ...
      implementation("androidx.compose.runtime:runtime-rxjava2:1.7.8")
}
dependencies {
      ...
      implementation "androidx.compose.runtime:runtime-rxjava2:1.7.8"
}
Kotlinดึงดูด
dependencies {
      ...
      implementation("androidx.compose.runtime:runtime-rxjava3:1.7.8")
}
dependencies {
      ...
      implementation "androidx.compose.runtime:runtime-rxjava3:1.7.8"
}

เก็บสถานะกับไม่เก็บสถานะ

Composable ที่ใช้ remember เพื่อจัดเก็บออบเจ็กต์จะสร้างสถานะภายใน ซึ่งทำให้ Composable เป็น Stateful HelloContent เป็นตัวอย่างของคอมโพสิชันที่มีสถานะเนื่องจากเก็บและแก้ไขสถานะ name ภายใน ซึ่งอาจมีประโยชน์ในสถานการณ์ที่ผู้โทรไม่จำเป็นต้องควบคุมสถานะและสามารถใช้งานได้โดยไม่ต้องจัดการสถานะด้วยตนเอง อย่างไรก็ตาม Composable ที่มีสถานะภายในมักจะนำกลับมาใช้ได้น้อยกว่าและทดสอบได้ยากขึ้น

คอมโพสิเบิลที่ไม่มีสถานะคือคอมโพสิเบิลที่ไม่มีสถานะใดๆ วิธีง่ายๆ ในการทำให้เป็นแบบไม่เก็บสถานะคือการใช้การยกสถานะ

ในการพัฒนา Composable ที่นำมาใช้ใหม่ได้ คุณมักต้องการแสดง Composable เดียวกันทั้งเวอร์ชันการเก็บสถานะและเวอร์ชันที่ไม่เก็บสถานะ เวอร์ชันที่มีสถานะจะสะดวกสำหรับผู้เรียกที่ไม่สนใจสถานะ ส่วนเวอร์ชันที่ไม่มีสถานะจำเป็นสำหรับผู้เรียกที่ต้องการควบคุมหรือยกสถานะ

บริการขนย้ายรัฐ

การยกระดับสถานะใน Compose เป็นรูปแบบการย้ายสถานะไปยังผู้เรียกของคอมโพสิเบิลเพื่อทำให้เป็นคอมโพสิเบิลที่ไม่มีสถานะ รูปแบบทั่วไปของการยกระดับสถานะใน Compose ของ Jetpack คือการใช้พารามิเตอร์ 2 รายการแทนตัวแปรสถานะ ดังนี้

  • value: T: ค่าปัจจุบันที่จะแสดง
  • onValueChange: (T) -> Unit: เหตุการณ์ที่ขอเปลี่ยนแปลงค่าโดยที่ T คือค่าใหม่ที่เสนอ

อย่างไรก็ตาม คุณไม่ได้จํากัดเพียง onValueChange หากเหตุการณ์ที่เฉพาะเจาะจงมากขึ้นเหมาะกับคอมโพสิเบิล คุณควรกําหนดเหตุการณ์เหล่านั้นโดยใช้ Lambda

สถานะที่ยกขึ้นด้วยวิธีนี้มีคุณสมบัติที่สำคัญบางอย่าง:

  • แหล่งข้อมูลที่เชื่อถือได้เพียงแหล่งเดียว: การย้ายสถานะแทนการทำซ้ำช่วยให้มั่นใจได้ว่าจะมีแหล่งข้อมูลที่เชื่อถือได้เพียงแหล่งเดียว ซึ่งจะช่วยหลีกเลี่ยงข้อบกพร่อง
  • Encapsulated: มีเพียงคอมโพสิเบิลที่มีสถานะเท่านั้นที่จะแก้ไขสถานะได้ การดำเนินการนี้เกิดขึ้นภายใน
  • แชร์ได้: แชร์สถานะที่มีการยกระดับกับคอมโพสิเบิลหลายรายการได้ หากต้องการอ่าน name ในคอมโพสิเบิลอื่น การยกระดับจะช่วยให้คุณทำเช่นนั้นได้
  • สามารถรับมือได้: ผู้เรียกใช้คอมโพสิเบิลแบบไม่มีสถานะสามารถเลือกที่จะเพิกเฉยหรือแก้ไขเหตุการณ์ก่อนที่จะเปลี่ยนสถานะได้
  • แยกส่วน: อาจมีการจัดเก็บสถานะของ Composable แบบไม่เก็บสถานะที่ใดก็ได้ ตัวอย่างเช่น คุณจะย้าย name ไปยัง ViewModel ได้

ในตัวอย่างนี้ คุณดึงข้อมูล name และ onValueChange จาก HelloContent แล้วเลื่อนขึ้นในโครงสร้างไปยัง HelloScreen Composable ที่เรียกใช้ 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 จะช่วยให้คุณหาเหตุผลเกี่ยวกับคอมโพสิเบิล นำมาใช้ซ้ำในสถานการณ์ต่างๆ และทำการทดสอบได้ง่ายขึ้น HelloContent แยกออกจากวิธีจัดเก็บสถานะ การแยกการเชื่อมโยงหมายความว่าหากแก้ไขหรือแทนที่ HelloScreen คุณไม่จําเป็นต้องเปลี่ยนวิธีติดตั้งใช้งาน HelloContent

รูปแบบที่สถานะลดลงและเหตุการณ์เพิ่มขึ้นเรียกว่าการไหลของข้อมูลแบบทิศทางเดียว ในกรณีนี้ สถานะจะลดลงจาก HelloScreen เป็น HelloContent และเหตุการณ์เพิ่มขึ้นจาก HelloContent เป็น HelloScreen การติดตามโฟลว์ข้อมูลที่เป็นทิศทางเดียวกันจะช่วยให้คุณสามารถแยก Composable ที่แสดงผลใน UI ออกจากส่วนต่างๆ ของแอปที่จัดเก็บและเปลี่ยนสถานะได้

ดูข้อมูลเพิ่มเติมได้ในหน้าตําแหน่งที่จะแสดงสถานะ

การกู้คืนสถานะในคอมโพสิท

rememberSaveable API มีลักษณะการทำงานคล้ายกับ remember เนื่องจากจะเก็บสถานะไว้ตลอดการคอมโพสิชันใหม่ รวมถึงการทํากิจกรรมหรือการสร้างกระบวนการใหม่โดยใช้กลไกสถานะอินสแตนซ์ที่บันทึกไว้ ตัวอย่างเช่น กรณีนี้เกิดขึ้นเมื่อหมุนหน้าจอ

วิธีจัดเก็บสถานะ

ระบบจะบันทึกประเภทข้อมูลทั้งหมดที่เพิ่มลงใน Bundle โดยอัตโนมัติ หากต้องการบันทึกสิ่งที่เพิ่มลงใน Bundle ไม่ได้ คุณมีตัวเลือกหลายอย่าง

แบ่งแปลงที่ดิน

วิธีที่ง่ายที่สุดคือเพิ่มคำอธิบายประกอบ @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 และใช้ดัชนีของ 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 หรือดูข้อมูลทั่วไปได้ในหน้าตัวเก็บสถานะและสถานะ UI ในคู่มือสถาปัตยกรรม

เรียกใช้การคํานวณการจดจําอีกครั้งเมื่อคีย์มีการเปลี่ยนแปลง

remember API มักใช้งานร่วมกับ MutableState ดังนี้

var name by remember { mutableStateOf("") }

ในที่นี้ การใช้ฟังก์ชัน remember จะทำให้ค่า MutableState คงอยู่ต่อไป

โดยทั่วไป remember จะใช้พารามิเตอร์ Lambda calculation เมื่อเรียกใช้ remember เป็นครั้งแรก ระบบจะเรียกใช้ Lambda ของ calculation และจัดเก็บผลลัพธ์ ในระหว่างการจัดองค์ประกอบใหม่ remember จะแสดงผลค่าที่จัดเก็บไว้ล่าสุด

นอกจากการแคชสถานะแล้ว คุณยังใช้ remember เพื่อจัดเก็บออบเจ็กต์หรือผลลัพธ์ของการดำเนินการในคอมโพสิชันที่ใช้เวลาในการเริ่มต้นหรือคำนวณนานได้ด้วย คุณอาจไม่ต้องการทําการคํานวณนี้ซ้ำทุกครั้งที่เปลี่ยนการผสม ตัวอย่างเช่น การสร้างออบเจ็กต์ ShaderBrush นี้ ซึ่งเป็นการดำเนินการที่มีค่าใช้จ่ายสูง

val brush = remember {
    ShaderBrush(
        BitmapShader(
            ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(),
            Shader.TileMode.REPEAT,
            Shader.TileMode.REPEAT
        )
    )
}

remember จะจัดเก็บค่าไว้จนกว่าค่านั้นจะออกจากการคอมโพสิชัน อย่างไรก็ตาม มีวิธีทำให้ค่าที่แคชไว้เป็นค่าที่ไม่ถูกต้อง นอกจากนี้ remember API ยังใช้พารามิเตอร์ key หรือ keys ด้วย หากคีย์ใดคีย์หนึ่งเหล่านี้มีการเปลี่ยนแปลง ครั้งถัดไปที่ฟังก์ชันคอมไพล์ใหม่ remember จะลบล้างแคชและดำเนินการคำนวณในบล็อก lambda อีกครั้ง กลไกนี้ช่วยให้คุณควบคุมอายุการใช้งานของออบเจ็กต์ในคอมโพสิชันได้ การคํานวณจะยังคงใช้งานได้จนกว่าอินพุตจะเปลี่ยนแปลง ไม่ใช่จนกว่าค่าที่จดจําไว้จะออกจากการคอมโพสิชัน

ตัวอย่างต่อไปนี้จะแสดงวิธีการทำงานของกลไกนี้

ในข้อมูลโค้ดนี้ ระบบจะสร้าง ShaderBrush และใช้เป็นการวาดพื้นหลังของคอมโพสิเบิล Box 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 ของคลาสเพื่อตัดสินใจว่าคีย์มีการเปลี่ยนแปลงหรือไม่และทำให้ค่าที่เก็บไว้เป็นโมฆะ

จัดเก็บสถานะด้วยคีย์นอกเหนือจากการจัดเรียงใหม่

rememberSaveable API คือ 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 ได้จากแหล่งข้อมูลเพิ่มเติมต่อไปนี้

ตัวอย่าง

Jetnews is a sample news reading app, built with Jetpack Compose. The goal of the sample is to showcase the current UI capabilities of Compose. To try out this sample app, use the latest stable version of Android Studio. You can clone this repository

Jetchat is a sample chat app built with Jetpack Compose. To try out this sample app, use the latest stable version of Android Studio. You can clone this repository or import the project from Android Studio following the steps here. This sample

Learn how this app was designed and built in the design case study, architecture learning journey and modularization learning journey. This is the repository for the Now in Android app. It is a work in progress 🚧. Now in Android is a fully functional

Codelab

วิดีโอ

บล็อก

Jetpack Compose is Android's recommended modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.

อัปเดตแล้ว Apr 9, 2025

Jetpack Compose is Android's recommended modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.

อัปเดตแล้ว Apr 9, 2025

Jetpack Compose is Android's recommended modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.

อัปเดตแล้ว Apr 9, 2025