บันทึกและจัดการสถานะการนําทาง

ส่วนต่อไปนี้จะอธิบายกลยุทธ์ในการบันทึกสแต็กย้อนกลับและจัดเก็บสถานะที่เชื่อมโยงกับรายการในสแต็กย้อนกลับ

บันทึกสแต็กย้อนกลับ

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

ใช้ rememberNavBackStack

ฟังก์ชันที่ประกอบกันได้ rememberNavBackStack ออกแบบมาเพื่อสร้างสแต็กย้อนกลับที่ยังคงอยู่ตลอดการเปลี่ยนแปลงการกำหนดค่าและการสิ้นสุดกระบวนการ

แต่ละคีย์ในสแต็กย้อนกลับต้องเป็นไปตามข้อกำหนดเฉพาะเพื่อให้ rememberNavBackStack ทำงานได้อย่างถูกต้อง ดังนี้

  • ใช้อินเทอร์เฟซ NavKey: ทุกคีย์ในสแต็กย้อนกลับต้องใช้ อินเทอร์เฟซ NavKey ซึ่งทำหน้าที่เป็นอินเทอร์เฟซมาร์กเกอร์ที่ส่งสัญญาณไปยังไลบรารีว่าคีย์สามารถบันทึกได้
  • มีคำอธิบายประกอบ @Serializable: นอกจากจะใช้ NavKey แล้ว คลาสและออบเจ็กต์คีย์ของคุณต้องมีคำอธิบายประกอบ @Serializable

ข้อมูลโค้ดต่อไปนี้แสดงการใช้งาน rememberNavBackStack อย่างถูกต้อง

@Serializable
data object Home : NavKey

@Composable
fun NavBackStack() {
    val backStack = rememberNavBackStack(Home)
}

จดจำสแต็กย้อนกลับที่มีประเภทย่อยของ NavKey

ฟังก์ชันที่ประกอบกันได้ rememberNavBackStack จะแสดงผล NavBackStack<NavKey> หากแอปกำหนดประเภทย่อยของ NavKey เองซึ่งคีย์ทั้งหมดสืบทอดมาจากประเภทย่อยนั้น คุณสามารถรักษาการพิมพ์นั้นไว้ได้โดยการใช้ฟังก์ชันจดจำที่กำหนดเอง ดังนี้

@Serializable
sealed interface MyAppNavKey : NavKey

@Serializable
data object ScreenA: MyAppNavKey

@Serializable
data class ScreenB(val id: String): MyAppNavKey

@Composable
fun rememberMyAppNavBackStack(vararg elements: MyAppNavKey): NavBackStack<MyAppNavKey> {
    return rememberSerializable(serializer = serializer()) {
        NavBackStack(*elements)
    }
}

@Composable
fun MyApp() {
    // defaultNavBackStack is NavBackStack<NavKey>
    val defaultNavBackStack = rememberNavBackStack(ScreenA)
    // myAppNavBackStack is NavBackStack<MyAppNavKey>
    val myAppNavBackStack = rememberMyAppNavBackStack(ScreenA)
}

ดูตัวอย่างเพิ่มเติม รวมถึงวิธีจัดการกับโพลีมอร์ฟิซึมแบบเปิดได้ที่ NavBackStackSamples

ทางเลือกอื่น: การจัดเก็บใน ViewModel

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

  • ตรวจสอบว่าคีย์เป็นแบบอนุกรมได้: คีย์การนำทางต้องเป็นแบบอนุกรมได้เช่นเดียวกับ rememberNavBackStack
  • จัดการการทำให้เป็นอนุกรมและการยกเลิกการทำให้เป็นอนุกรมด้วยตนเอง: คุณมีหน้าที่รับผิดชอบในการ บันทึกการแสดงแบบอนุกรมของแต่ละคีย์ลงในพื้นที่เก็บข้อมูลถาวร (เช่น SharedPreferences, ฐานข้อมูล หรือไฟล์) และ ยกเลิกการทำให้เป็นอนุกรมจากพื้นที่เก็บข้อมูลดังกล่าวด้วยตนเองเมื่อแอปเข้าสู่เบื้องหลังหรือได้รับการ กู้คืน

การกำหนดขอบเขตอินสแตนซ์ ViewModel ให้กับออบเจ็กต์ NavEntry

ViewModels ใช้เพื่อเก็บสถานะที่เกี่ยวข้องกับ UI ไว้ตลอดการเปลี่ยนแปลงการกำหนดค่า เช่น การหมุนหน้าจอ โดยค่าเริ่มต้น ViewModels จะกำหนดขอบเขตไว้ที่ ViewModelStoreOwner ที่ใกล้ที่สุด ซึ่งโดยปกติจะเป็น Activity หรือ Fragment

อย่างไรก็ตาม คุณอาจต้องการกำหนดขอบเขต ViewModel ให้กับ NavEntry ที่เฉพาะเจาะจง (เช่น หน้าจอหรือปลายทางที่เฉพาะเจาะจง) ในสแต็กย้อนกลับแทนที่จะเป็น Activity ทั้งหมด ซึ่งจะช่วยให้มั่นใจได้ว่าสถานะของ ViewModel จะยังคงอยู่เฉพาะในขณะที่ NavEntry นั้นเป็นส่วนหนึ่งของสแต็กย้อนกลับ และจะถูกล้างเมื่อมีการนำ NavEntry ออก

ไลบรารีเสริม androidx.lifecycle:lifecycle-viewmodel-navigation3 มี NavEntryDecorator ที่ช่วยให้ทำเช่นนี้ได้ ตัวตกแต่งนี้มี ViewModelStoreOwner สำหรับแต่ละ NavEntry เมื่อคุณสร้าง ViewModel ภายในเนื้อหาของ NavEntry (เช่น ใช้ viewModel() ใน Compose) ระบบจะกำหนดขอบเขตให้กับคีย์ของ NavEntry ที่เฉพาะเจาะจงนั้นในสแต็กย้อนกลับโดยอัตโนมัติ ซึ่งหมายความว่าระบบจะสร้าง ViewModel เมื่อมีการเพิ่ม NavEntry ลงในสแต็กย้อนกลับ และจะล้างเมื่อมีการนำออก

หากต้องการใช้ NavEntryDecorator เพื่อกำหนดขอบเขต ViewModel ให้กับ NavEntry ให้ทำตามขั้นตอนต่อไปนี้

  1. เพิ่มทรัพยากร Dependency androidx.lifecycle:lifecycle-viewmodel-navigation3 ลงในไฟล์ app/build.gradle.kts
  2. เพิ่มค่าเริ่มต้น rememberSaveableStateHolderNavEntryDecorator() ลงในรายการ entryDecorators เมื่อสร้าง NavDisplay
  3. เพิ่ม rememberViewModelStoreNavEntryDecorator() ลงในรายการ entryDecorators

NavDisplay(
    entryDecorators = listOf(
        // Add the default decorators for managing scenes and saving state
        rememberSaveableStateHolderNavEntryDecorator(),
        // Then add the view model store decorator
        rememberViewModelStoreNavEntryDecorator()
    ),
    backStack = backStack,
    entryProvider = entryProvider { },
)