ย้าย 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

หากต้องการย้ายไปยังการเขียนในการนำทาง ให้ทำตามขั้นตอนต่อไปนี้

  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 ในตำแหน่งที่ Composable ทั้งหมดที่ต้องใช้การอ้างอิงจะมีสิทธิ์เข้าถึง (โดยปกติจะอยู่ใน Composable ของ 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

เรียกข้อมูลที่ซับซ้อนขณะนำทาง

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

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

ข้อจำกัด

ส่วนนี้จะอธิบายข้อจํากัดปัจจุบันของ 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