State และ Jetpack Compose

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

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

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

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

สถานะและการสร้าง UI

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

ดูข้อมูลเพิ่มเติมเกี่ยวกับการสร้าง UI ครั้งแรกและการสร้าง UI ใหม่ได้ที่ การคิดแบบ Compose

สถานะใน Composable

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

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

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

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

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

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

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

  • Flow: collectAsStateWithLifecycle()

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

    คุณต้องมีทรัพยากร Dependency ต่อไปนี้ในไฟล์ build.gradle (ควร เป็นเวอร์ชัน 2.6.0-beta01 ขึ้นไป)

Kotlin

dependencies {
      ...
      implementation("androidx.lifecycle:lifecycle-runtime-compose:2.10.0")
}

ดึงดูด

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

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

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

    collectAsState ไม่ต้องใช้ทรัพยากร Dependency เพิ่มเติม เนื่องจากมีอยู่ใน compose-runtime

  • LiveData: observeAsState()

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

    คุณต้องมีทรัพยากร Dependency ต่อไปนี้ในไฟล์ build.gradle

Kotlin

dependencies {
      ...
      implementation("androidx.compose.runtime:runtime-livedata:1.10.5")
}

ดึงดูด

dependencies {
      ...
      implementation "androidx.compose.runtime:runtime-livedata:1.10.5"
}
  • RxJava2: subscribeAsState()

    subscribeAsState() เป็นฟังก์ชันส่วนขยายที่แปลงสตรีมแบบโต้ตอบของ RxJava2 (เช่น Single, Observable, Completable) เป็น State ของ Compose

    คุณต้องมีทรัพยากร Dependency ต่อไปนี้ในไฟล์ build.gradle

Kotlin

dependencies {
      ...
      implementation("androidx.compose.runtime:runtime-rxjava2:1.10.5")
}

ดึงดูด

dependencies {
      ...
      implementation "androidx.compose.runtime:runtime-rxjava2:1.10.5"
}
  • RxJava3: subscribeAsState()

    subscribeAsState() เป็นฟังก์ชันส่วนขยายที่แปลงสตรีมแบบโต้ตอบของ RxJava3 (เช่น Single, Observable, Completable) เป็น State ของ Compose

    คุณต้องมีทรัพยากร Dependency ต่อไปนี้ในไฟล์ build.gradle

Kotlin

dependencies {
      ...
      implementation("androidx.compose.runtime:runtime-rxjava3:1.10.5")
}

ดึงดูด

dependencies {
      ...
      implementation "androidx.compose.runtime:runtime-rxjava3:1.10.5"
}

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

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

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

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

การย้ายสถานะ

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

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

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

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

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

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

การกู้คืนสถานะใน Compose

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

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

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

Parcelize

โซลูชันที่ง่ายที่สุดคือการเพิ่ม @Parcelize คำอธิบายประกอบลงในออบเจ็กต์ ออบเจ็กต์จะกลายเป็น Parcelable และสามารถจัดกลุ่มได้ ตัวอย่างเช่น โค้ดนี้จะสร้างประเภทข้อมูล City ที่เป็น Parcelable และบันทึกลงในสถานะ

@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

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

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

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

API remember มักใช้ร่วมกับ MutableState

var name by remember { mutableStateOf("") }

ในที่นี้ การใช้ฟังก์ชัน remember จะทำให้ค่า MutableState ยังคงอยู่ตลอดการสร้าง UI ใหม่

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

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

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

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

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

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

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

API rememberSaveable เป็น Wrapper สำหรับ remember ที่สามารถจัดเก็บ ข้อมูลใน Bundle ได้ API นี้ช่วยให้สถานะยังคงอยู่ได้ไม่เพียงแค่ตลอดการสร้าง UI ใหม่ แต่ยังรวมถึงการสร้างกิจกรรมใหม่และการสิ้นสุดการประมวลผลที่ระบบเริ่มด้วย rememberSaveable จะรับพารามิเตอร์ input เพื่อวัตถุประสงค์เดียวกับที่ remember รับ keys ระบบจะล้างแคชเมื่ออินพุตใดก็ตามมีการเปลี่ยนแปลง เมื่อฟังก์ชันสร้าง UI ใหม่ในครั้งถัดไป rememberSaveable จะเรียกใช้บล็อก Lambda calculation อีกครั้ง

ในตัวอย่างต่อไปนี้ rememberSaveable จะจัดเก็บ userTypedQuery ไว้จนกว่า typedQuery จะมีการเปลี่ยนแปลง

var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) {
    mutableStateOf(
        TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length))
    )
}

ดูข้อมูลเพิ่มเติม

ดูข้อมูลเพิ่มเติมเกี่ยวกับสถานะและ Jetpack Compose ได้จากแหล่งข้อมูลเพิ่มเติมต่อไปนี้

ตัวอย่าง

Codelab

วิดีโอ

บล็อก