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

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

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

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

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

ขั้นตอนการย้ายโปรเจ็กต์

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

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

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

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

    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 เป็นแหล่งข้อมูลที่ถูกต้องเพียงแหล่งเดียวสำหรับการไปยังส่วนต่างๆ ระหว่างหน้าจอที่ประกอบได้และรักษา Back Stack ไว้

    @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 แล้ว ขั้นตอนนี้จะมีเพียงการ ดึงข้อมูล Composable ของหน้าจอเหล่านี้จาก Fragment ไปยัง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 และเหตุการณ์การนำทางไปยัง Composables ขั้นตอนถัดไปคือการเปลี่ยนวิธีระบุ ViewModel ให้กับ Composables ของแต่ละหน้าจอ คุณมักจะใช้การแทรก Hilt และจุดผสานรวมกับ Compose และ Navigation ผ่าน hiltViewModel ได้

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

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

    คุณส่งข้อมูลไปยังปลายทางได้โดยการสร้างอินสแตนซ์ของคลาสเส้นทางที่กำหนดไว้สำหรับปลายทางนั้น จากนั้นคุณจะรับได้โดยตรง จากรายการใน Back Stack ที่ปลายทาง หรือจาก 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. นำ Fragment, เลย์เอาต์ XML ที่เกี่ยวข้อง, การนำทางที่ไม่จำเป็น และทรัพยากรอื่นๆ รวมถึง Fragment ที่ล้าสมัยและทรัพยากร Dependency ของ Jetpack Navigation ออก

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

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

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

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

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

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

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

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

ข้อจำกัด

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

การย้ายข้อมูลไปยัง Navigation Compose แบบค่อยเป็นค่อยไป

ขณะนี้คุณยังใช้ Navigation Compose ไม่ได้ในขณะที่ยังใช้ Fragment เป็น ปลายทางในโค้ด หากต้องการเริ่มใช้ Navigation Compose ปลายทางทั้งหมดของคุณต้องเป็น Composable คุณติดตามคำขอฟีเจอร์นี้ได้ใน Issue Tracker

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

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

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

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

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