ย้าย Jetpack การนำทางไปยัง Navigation Compose

Navigation Compose API ช่วยให้คุณไปยังส่วนต่างๆ ของคอมโพสิเบิลในแอป Compose ได้ พร้อมทั้งใช้ประโยชน์จากคอมโพเนนต์ โครงสร้างพื้นฐาน และฟีเจอร์ของ Jetpack Navigation

หน้านี้อธิบายวิธีย้ายข้อมูลจาก Jetpack Navigation ที่ใช้ Fregment ไปยัง Navigation Compose ซึ่งเป็นส่วนหนึ่งของการย้ายข้อมูล UI ขนาดใหญ่ที่ใช้ View ไปยัง Jetpack Compose

ข้อกําหนดเบื้องต้นในการย้ายข้อมูล

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

การใช้ Navigation Compose ในแอป Compose เท่านั้นไม่ใช่ข้อกําหนดเบื้องต้น คุณใช้ คอมโพเนนต์การนำทางที่อิงตามข้อมูลโค้ดต่อไปได้ ตราบใดที่คุณยังใช้ข้อมูลโค้ดเพื่อโฮสต์เนื้อหาที่คอมโพสิเบิล

ขั้นตอนการย้ายข้อมูล

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

หากแอปของคุณเป็นไปตามรูปแบบการออกแบบ UDF และคำแนะนำเกี่ยวกับสถาปัตยกรรมอยู่แล้ว การย้ายข้อมูลไปยัง Jetpack Compose และ Navigation Compose จะไม่จําเป็นต้องรีแฟกทอริงเลเยอร์อื่นๆ ของแอปมากนัก ยกเว้นเลเยอร์ UI

หากต้องการย้ายข้อมูลไปยัง Navigation Compose ให้ทําตามขั้นตอนต่อไปนี้

  1. เพิ่มทรัพยากร Dependency ของ Navigation Compose ลงในแอป
  2. สร้างคอมโพสิชัน App-level แล้วเพิ่มลงใน Activity ของคุณเป็นจุดแรกเข้าของคอมโพสิชัน แทนการตั้งค่าเลย์เอาต์มุมมอง ดังนี้

    class SampleActivity : ComponentActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            // setContentView<ActivitySampleBinding>(this, R.layout.activity_sample)
            setContent {
                SampleApp(/* ... */)
            }
        }
    }

  3. สร้างประเภทสําหรับปลายทางการนําทางแต่ละแห่ง ใช้ data object สำหรับปลายทางที่ไม่ต้องใช้ข้อมูล และ data class หรือ class สำหรับปลายทางที่ต้องใช้ข้อมูล

    @Serializable data object First
    @Serializable data class Second(val id: String)
    @Serializable data object Third
    

  4. ตั้งค่า NavController ไว้ในตำแหน่งที่คอมโพสิเบิลทั้งหมดที่ต้องอ้างอิงเข้าถึงได้ (โดยปกติจะอยู่ภายในคอมโพสิเบิล App) แนวทางนี้เป็นไปตามหลักการของการยกระดับสถานะ และให้คุณใช้ NavController เป็นแหล่งข้อมูลสำหรับการไปยังส่วนต่างๆ ของหน้าจอแบบคอมโพสิเบิลและดูแลรักษากองซ้อนที่ซ้อนกันอยู่

    @Composable
    fun SampleApp() {
        val navController = rememberNavController()
        // ...
    }

  5. สร้าง NavHost ของแอปภายในคอมโพสิชัน App และส่ง navController ดังนี้

    @Composable
    fun SampleApp() {
        val navController = rememberNavController()
    
        SampleNavHost(navController = navController)
    }
    
    @Composable
    fun SampleNavHost(
        navController: NavHostController
    ) {
        NavHost(navController = navController, startDestination = First) {
            // ...
        }
    }

  6. เพิ่มปลายทาง composable เพื่อสร้างกราฟการนำทาง หากย้ายข้อมูลหน้าจอแต่ละหน้าจอไปยัง Compose ไว้ก่อนหน้านี้แล้ว ขั้นตอนนี้จะมีเพียงการดึงข้อมูลคอมโพสิชันหน้าจอเหล่านี้จาก Fregment ไปยังปลายทางcomposableต่อไปนี้

    class FirstFragment : Fragment() {
    
        override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View {
            return ComposeView(requireContext()).apply {
                setContent {
                    // FirstScreen(...) EXTRACT FROM HERE
                }
            }
        }
    }
    
    @Composable
    fun SampleNavHost(
        navController: NavHostController
    ) {
        NavHost(navController = navController, startDestination = First) {
            composable<First> {
                FirstScreen(/* ... */) // EXTRACT TO HERE
            }
            composable<Second> {
                SecondScreen(/* ... */)
            }
            // ...
        }
    }

  7. หากคุณทําตามคําแนะนําเกี่ยวกับการจัดโครงสร้าง UI ของ Compose โดยเฉพาะวิธีส่ง ViewModel และเหตุการณ์การนําทางไปยัง Composable ขั้นตอนถัดไปคือเปลี่ยนวิธีระบุ ViewModel ให้กับ Composable แต่ละหน้าจอ คุณมักจะใช้การฉีด Hilt และจุดผสานรวมกับ Compose และ Navigation ผ่าน hiltViewModel ได้ดังนี้

    @Composable
    fun FirstScreen(
        // viewModel: FirstViewModel = viewModel(),
        viewModel: FirstViewModel = hiltViewModel(),
        onButtonClick: () -> Unit = {},
    ) {
        // ...
    }

  8. แทนที่การเรียกใช้การนําทาง findNavController() ทั้งหมดด้วย navController และส่งการเรียกใช้เหล่านี้เป็นเหตุการณ์การนําทางไปยังหน้าจอคอมโพสิเบิลแต่ละหน้าจอแทนการส่ง navController ทั้งหมด แนวทางนี้เป็นไปตามแนวทางปฏิบัติแนะนำในการแสดงเหตุการณ์จากฟังก์ชันคอมโพสิเบิลต่อผู้เรียกใช้ และทำให้ navController เป็นแหล่งข้อมูลที่ถูกต้องเพียงแหล่งเดียว

    คุณสามารถส่งข้อมูลไปยังปลายทางได้โดยการสร้างอินสแตนซ์ของคลาสเส้นทางที่กําหนดไว้สําหรับปลายทางนั้น จากนั้นคุณก็รับ ViewModel ได้จากรายการสแต็กด้านหลังที่ปลายทางโดยตรง หรือจาก ViewModel โดยใช้ SavedStateHandle.toRoute()

    @Composable
    fun SampleNavHost(
        navController: NavHostController
    ) {
        NavHost(navController = navController, startDestination = First) {
            composable<First> {
                FirstScreen(
                    onButtonClick = {
                        // findNavController().navigate(firstScreenToSecondScreenAction)
                        navController.navigate(Second(id = "ABC"))
                    }
                )
            }
            composable<Second> { backStackEntry ->
                val secondRoute = backStackEntry.toRoute<Second>()
                SecondScreen(
                    id = secondRoute.id,
                    onIconClick = {
                        // findNavController().navigate(secondScreenToThirdScreenAction)
                        navController.navigate(Third)
                    }
                )
            }
            // ...
        }
    }

  9. ลบ Fregment, เลย์เอาต์ XML ที่เกี่ยวข้อง, การนำทางและทรัพยากรอื่นๆ ที่ไม่จำเป็น รวมถึงการพึ่งพา Fregment และการนำทางของ Jetpack ที่ล้าสมัย

คุณดูขั้นตอนเดียวกันพร้อมรายละเอียดเพิ่มเติมเกี่ยวกับ Navigation Compose ได้ในเอกสารประกอบการตั้งค่า

กรณีการใช้งานทั่วไป

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

กรณีการใช้งานทั่วไปเมื่อย้ายข้อมูลมีดังนี้

ดูข้อมูลโดยละเอียดเพิ่มเติมเกี่ยวกับกรณีการใช้งานเหล่านี้ได้ที่การไปยังส่วนต่างๆ ด้วย Compose

ดึงข้อมูลที่ซับซ้อนเมื่อนำทาง

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

หากมีการส่งออบเจ็กต์ที่ซับซ้อนเป็นอาร์กิวเมนต์ ให้ลองปรับโครงสร้างโค้ดก่อน โดยให้สามารถจัดเก็บและดึงข้อมูลออบเจ็กต์เหล่านี้จากเลเยอร์ข้อมูล ดูตัวอย่างได้ที่ที่เก็บ Now in Android

ข้อจำกัด

ส่วนนี้จะอธิบายข้อจํากัดปัจจุบันของ Navigation Compose

การย้ายข้อมูลไปยัง Navigation Compose เพิ่มขึ้น

ปัจจุบันคุณใช้ Navigation Compose ไม่ได้ขณะที่ยังคงใช้ Fragments เป็นปลายทางในโค้ด หากต้องการเริ่มใช้ Navigation Compose ปลายทางทั้งหมดต้องเป็นแบบคอมโพสิเบิล คุณติดตามคำขอฟีเจอร์นี้ในเครื่องมือติดตามปัญหาได้

ภาพเคลื่อนไหวของการเปลี่ยน

ตั้งแต่ Navigation 2.7.0-alpha01 เป็นต้นไป NavHost จะรองรับการตั้งค่าทรานซิชันที่กำหนดเองโดยตรง ซึ่งก่อนหน้านี้รองรับใน AnimatedNavHost อ่านบันทึกประจำรุ่นเพื่อดูข้อมูลเพิ่มเติม

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

ดูข้อมูลเพิ่มเติมเกี่ยวกับการย้ายข้อมูลไปยัง Navigation Compose ได้ที่แหล่งข้อมูลต่อไปนี้

  • Navigation Compose Codelab: ดูข้อมูลเบื้องต้นเกี่ยวกับ Navigation Compose ด้วย Codelab แบบปฏิบัติจริง
  • ตอนนี้อยู่ในที่เก็บข้อมูล Android: แอป Android ที่ใช้งานได้อย่างเต็มรูปแบบซึ่งสร้างขึ้นด้วย Kotlin และ Jetpack Compose ทั้งหมด โดยเป็นไปตามแนวทางปฏิบัติแนะนำด้านการออกแบบและพัฒนาของ Android และมี Navigation Compose
  • การย้ายข้อมูล Sunflower ไปยัง Jetpack Compose: บล็อกโพสต์ที่บันทึกเส้นทางการย้ายข้อมูลของแอปตัวอย่าง Sunflower จาก Views ไปยัง Compose ซึ่งรวมถึงการย้ายข้อมูลไปยัง Navigation Compose ด้วย
  • Jetnews สำหรับทุกหน้าจอ: บล็อกโพสต์ที่บันทึกการแยกส่วนและย้ายข้อมูลตัวอย่าง Jetnews เพื่อรองรับหน้าจอทั้งหมดด้วย Jetpack Compose และ Navigation Compose