การนำทางช่วยให้คุณแนบข้อมูลไปยังการดำเนินการนำทางได้โดยกำหนดอาร์กิวเมนต์สำหรับปลายทาง เช่น ปลายทางโปรไฟล์ผู้ใช้อาจใช้อาร์กิวเมนต์รหัสผู้ใช้เพื่อระบุผู้ใช้ที่จะแสดง
โดยทั่วไป คุณควรส่งข้อมูลเพียงจํานวนน้อยที่สุดระหว่างปลายทาง เช่น คุณควรส่งคีย์เพื่อเรียกข้อมูลออบเจ็กต์ แทนการส่งออบเจ็กต์นั้นๆ เนื่องจากพื้นที่เก็บข้อมูลทั้งหมดสำหรับสถานะที่บันทึกไว้ทั้งหมดมีขีดจำกัดใน Android หากต้องการส่งข้อมูลจํานวนมาก ให้ใช้ ViewModel
ตามที่อธิบายไว้ในภาพรวมของ ViewModel
กำหนดอาร์กิวเมนต์ปลายทาง
หากต้องการส่งข้อมูลระหว่างปลายทาง ให้กําหนดอาร์กิวเมนต์ก่อนโดยเพิ่มลงในปลายทางที่รับข้อมูล โดยทําตามขั้นตอนต่อไปนี้
- ในเครื่องมือแก้ไขการนําทาง ให้คลิกปลายทางที่รับอาร์กิวเมนต์
- ในแผงแอตทริบิวต์ ให้คลิกเพิ่ม (+)
- ในหน้าต่างเพิ่มลิงก์อาร์กิวเมนต์ที่ปรากฏขึ้น ให้ป้อนชื่ออาร์กิวเมนต์ ประเภทอาร์กิวเมนต์ ระบุว่าอาร์กิวเมนต์เป็นค่าที่อนุญาตหรือไม่ และค่าเริ่มต้น หากจำเป็น
- คลิกเพิ่ม โปรดทราบว่าตอนนี้อาร์กิวเมนต์จะปรากฏในรายการอาร์กิวเมนต์ในแผงแอตทริบิวต์
- จากนั้นคลิกการดําเนินการที่เกี่ยวข้องซึ่งนําคุณไปยังปลายทางนี้ ในแผงแอตทริบิวต์ คุณควรเห็นอาร์กิวเมนต์ที่เพิ่มใหม่ในส่วนค่าเริ่มต้นของอาร์กิวเมนต์
นอกจากนี้ คุณยังเห็นว่ามีการเพิ่มอาร์กิวเมนต์ใน XML ด้วย คลิกแท็บข้อความเพื่อสลับไปยังมุมมอง XML และสังเกตว่าระบบได้เพิ่มอาร์กิวเมนต์ของคุณไปยังปลายทางที่รับอาร์กิวเมนต์ ตัวอย่างแสดงอยู่ด้านล่าง
<fragment android:id="@+id/myFragment" > <argument android:name="myArg" app:argType="integer" android:defaultValue="0" /> </fragment>
ประเภทอาร์กิวเมนต์ที่รองรับ
ไลบรารีการนําทางรองรับประเภทอาร์กิวเมนต์ต่อไปนี้
ประเภท | ไวยากรณ์ app:argType | การรองรับค่าเริ่มต้น | จัดการโดยเส้นทาง | เว้นว่างได้ |
---|---|---|---|---|
จำนวนเต็ม | app:argType="integer" | ใช่ | ได้ | ไม่ |
ล่องลอย | app:argType="float" | ใช่ | ได้ | ไม่ |
ยาว | app:argType="long" | ใช่ - ค่าเริ่มต้นต้องลงท้ายด้วยส่วนต่อท้าย "L" เสมอ (เช่น "123L") | ใช่ | ไม่ |
บูลีน | app:argType="boolean" | ใช่ - "จริง" หรือ "เท็จ" | ใช่ | ไม่ |
สตริง | app:argType="string" | ใช่ | ได้ | ใช่ |
การอ้างอิงทรัพยากร | app:argType="reference" | ได้ - ค่าเริ่มต้นต้องอยู่ในรูปแบบ "@resourceType/resourceName" (เช่น "@style/myCustomStyle") หรือ "0" | ใช่ | ไม่ |
Parcelable ที่กําหนดเอง | app:argType="<type>" โดยที่ <type> คือชื่อคลาสที่สมบูรณ์ในตัวเองของ Parcelable |
รองรับค่าเริ่มต้น "@null" ไม่รองรับค่าเริ่มต้นอื่นๆ | ไม่ | ใช่ |
Serializable ที่กําหนดเอง | app:argType="<type>" โดยที่ <type> คือชื่อคลาสที่สมบูรณ์ในตัวเองของ Serializable |
รองรับค่าเริ่มต้น "@null" ไม่รองรับค่าเริ่มต้นอื่นๆ | ไม่ | ใช่ |
Enum ที่กําหนดเอง | app:argType="<type>" โดยที่ <type> คือชื่อที่สมบูรณ์ในตัวเองของ enum | ใช่ - ค่าเริ่มต้นต้องตรงกับชื่อที่ไม่มีข้อจำกัดความ (เช่น "SUCCESS" เพื่อจับคู่กับ MyEnum.SUCCESS) | ไม่ | ไม่ |
หากประเภทอาร์กิวเมนต์รองรับค่า Null คุณสามารถประกาศค่าเริ่มต้นเป็น Null ได้โดยใช้ android:defaultValue="@null"
ระบบจะแยกวิเคราะห์เส้นทาง, Deep Link และ URI พร้อมอาร์กิวเมนต์จากสตริงได้ ซึ่งไม่สามารถทำได้โดยใช้ประเภทข้อมูลที่กําหนดเอง เช่น Parcelables และ Serializable ดังที่เห็นในตารางก่อนหน้า หากต้องการส่งผ่านข้อมูลที่ซับซ้อนที่กําหนดเอง ให้จัดเก็บข้อมูลไว้ที่อื่น เช่น ViewModel หรือฐานข้อมูล และส่งผ่านตัวระบุขณะไปยังส่วนต่างๆ เท่านั้น จากนั้นดึงข้อมูลในตําแหน่งใหม่หลังจากไปยังส่วนต่างๆ เสร็จแล้ว
เมื่อเลือกประเภทที่กำหนดเองรายการใดรายการหนึ่ง กล่องโต้ตอบเลือกชั้นเรียนจะปรากฏขึ้นและแจ้งให้คุณเลือกชั้นเรียนที่เกี่ยวข้องสำหรับประเภทนั้น แท็บโปรเจ็กต์จะให้คุณเลือกชั้นเรียนจากโปรเจ็กต์ปัจจุบัน
คุณเลือก <inferred type> เพื่อให้คลังการนำทางระบุประเภทตามค่าที่ระบุได้
คุณสามารถเลือกอาร์เรย์เพื่อระบุว่าอาร์กิวเมนต์ควรเป็นอาร์เรย์ของค่าประเภทที่เลือก ข้อควรทราบ
- ระบบไม่รองรับอาร์เรย์ของ Enum และอาร์เรย์ของการอ้างอิงทรัพยากร
- อาร์เรย์รองรับค่าที่อนุญาตค่า Null โดยไม่คำนึงถึงการสนับสนุนค่าที่อนุญาตค่า Null ของประเภทพื้นฐาน ตัวอย่างเช่น การใช้
app:argType="integer[]"
จะช่วยให้คุณใช้app:nullable="true"
เพื่อระบุว่าระบบยอมรับการพาสอาร์เรย์ Null ได้ - อาร์เรย์รองรับค่าเริ่มต้นค่าเดียว "@null" อาร์เรย์ไม่รองรับค่าเริ่มต้นอื่นๆ
ลบล้างอาร์กิวเมนต์ปลายทางในการดําเนินการ
การดำเนินการทั้งหมดที่ไปยังปลายทางจะใช้อาร์กิวเมนต์ระดับปลายทางและค่าเริ่มต้น หากจําเป็น คุณสามารถลบล้างค่าเริ่มต้นของอาร์กิวเมนต์ (หรือตั้งค่าหากยังไม่มี) ได้โดยกําหนดอาร์กิวเมนต์ที่ระดับการดําเนินการ โดยอาร์กิวเมนต์นี้ต้องมีชื่อและประเภทเดียวกับอาร์กิวเมนต์ที่ประกาศไว้ในปลายทาง
XML ต่อไปนี้ประกาศการดำเนินการที่มีอาร์กิวเมนต์ซึ่งลบล้างอาร์กิวเมนต์ระดับปลายทางจากตัวอย่างก่อนหน้า
<action android:id="@+id/startMyFragment"
app:destination="@+id/myFragment">
<argument
android:name="myArg"
app:argType="integer"
android:defaultValue="1" />
</action>
ใช้ Safe Args เพื่อส่งข้อมูลโดยที่ปลอดภัยจากประเภท
คอมโพเนนต์การนำทางมีพลักอิน Gradle ชื่อ Safe Args ที่สร้างคลาสออบเจ็กต์และคลาสบิลเดอร์แบบง่ายสำหรับการนําทางที่ปลอดภัยตามประเภทและการเข้าถึงอาร์กิวเมนต์ที่เกี่ยวข้อง เราขอแนะนำอย่างยิ่งให้ใช้ Safe Args ในการไปยังส่วนต่างๆ และส่งผ่านข้อมูล เนื่องจากช่วยให้มั่นใจได้ว่าประเภทข้อมูลจะปลอดภัย
หากไม่ได้ใช้ Gradle คุณจะใช้ปลั๊กอิน Safe Args ไม่ได้ ในกรณีเหล่านี้ คุณสามารถใช้ Bundle เพื่อส่งผ่านข้อมูลได้โดยตรง
หากต้องการเพิ่ม Safe Args ลงในโปรเจ็กต์ ให้ใส่ classpath
ต่อไปนี้ในไฟล์ build.gradle
ระดับบนสุด
Groovy
buildscript { repositories { google() } dependencies { def nav_version = "2.8.4" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" } }
Kotlin
buildscript { repositories { google() } dependencies { val nav_version = "2.8.4" classpath("androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version") } }
นอกจากนี้ คุณยังต้องใช้ปลั๊กอิน 1 ใน 2 รายการที่มีให้
หากต้องการสร้างโค้ดภาษา Java ที่เหมาะสมกับโมดูล Java หรือโมดูล Java และ Kotlin แบบผสม ให้เพิ่มบรรทัดนี้ลงในไฟล์ build.gradle
ของแอปหรือโมดูล
Groovy
plugins { id 'androidx.navigation.safeargs' }
Kotlin
plugins { id("androidx.navigation.safeargs") }
หรือหากต้องการสร้างโค้ด Kotlin ที่เหมาะสมสําหรับโมดูล Kotlin เท่านั้น ให้เพิ่ม
Groovy
plugins { id 'androidx.navigation.safeargs.kotlin' }
Kotlin
plugins { id("androidx.navigation.safeargs.kotlin") }
คุณต้องมี android.useAndroidX=true
ในไฟล์ gradle.properties
ตามหัวข้อการย้ายข้อมูลไปยัง AndroidX
หลังจากเปิดใช้ Safe Args แล้ว โค้ดที่สร้างขึ้นจะมีคลาสและเมธอดที่ปลอดภัยประเภทต่อไปนี้สําหรับการดำเนินการแต่ละรายการ รวมถึงปลายทางการส่งและปลายทางการรับแต่ละรายการ
ระบบจะสร้างคลาสสําหรับปลายทางแต่ละแห่งที่เป็นแหล่งที่มาของการดำเนินการ ชื่อของคลาสนี้คือชื่อของปลายทางต้นทางต่อท้ายด้วยคำว่า "เส้นทาง" เช่น หากปลายทางต้นทางคือข้อมูลโค้ดที่ชื่อ
SpecifyAmountFragment
คลาสที่สร้างขึ้นจะมีชื่อว่าSpecifyAmountFragmentDirections
คลาสนี้มีเมธอดสําหรับการดําเนินการแต่ละรายการที่กําหนดไว้ในต้นทางและปลายทาง
สําหรับการดําเนินการแต่ละรายการที่ใช้ส่งอาร์กิวเมนต์ ระบบจะสร้างคลาสภายในที่มีชื่อตามการดําเนินการนั้น เช่น หากการดําเนินการเรียกว่า
confirmationAction,
คลาสจะชื่อConfirmationAction
หากการดําเนินการของคุณมีพารามิเตอร์ที่ไม่มีdefaultValue
คุณจะใช้คลาสการดําเนินการที่เกี่ยวข้องเพื่อกําหนดค่าของพารามิเตอร์ระบบจะสร้างชั้นเรียนสําหรับปลายทางที่รับ ชื่อของคลาสนี้คือชื่อปลายทางต่อท้ายด้วยคำว่า "Args" เช่น หากข้อมูลโค้ดปลายทางชื่อ
ConfirmationFragment,
คลาสที่สร้างขึ้นจะชื่อConfirmationFragmentArgs
ใช้fromBundle()
เมธอดของคลาสนี้เพื่อดึงข้อมูลอาร์กิวเมนต์
ตัวอย่างต่อไปนี้แสดงวิธีใช้เมธอดเหล่านี้เพื่อตั้งค่าอาร์กิวเมนต์และส่งไปยังเมธอด navigate()
Kotlin
override fun onClick(v: View) { val amountTv: EditText = view!!.findViewById(R.id.editTextAmount) val amount = amountTv.text.toString().toInt() val action = SpecifyAmountFragmentDirections.confirmationAction(amount) v.findNavController().navigate(action) }
Java
@Override public void onClick(View view) { EditText amountTv = (EditText) getView().findViewById(R.id.editTextAmount); int amount = Integer.parseInt(amountTv.getText().toString()); ConfirmationAction action = SpecifyAmountFragmentDirections.confirmationAction(); action.setAmount(amount); Navigation.findNavController(view).navigate(action); }
ในโค้ดสําหรับปลายทางที่รับ ให้ใช้เมธอด getArguments()
เพื่อดึงข้อมูลกลุ่มและใช้เนื้อหา เมื่อใช้ -ktx
ผู้ใช้ Kotlin จะใช้ตัวรับมอบสิทธิ์พร็อพเพอร์ตี้ by navArgs()
เพื่อเข้าถึงอาร์กิวเมนต์ได้ด้วย
Kotlin
val args: ConfirmationFragmentArgs by navArgs() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val tv: TextView = view.findViewById(R.id.textViewAmount) val amount = args.amount tv.text = amount.toString() }
Java
@Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { TextView tv = view.findViewById(R.id.textViewAmount); int amount = ConfirmationFragmentArgs.fromBundle(getArguments()).getAmount(); tv.setText(amount + ""); }
ใช้ Safe Args กับการดำเนินการส่วนกลาง
เมื่อใช้ Safe Args กับการดำเนินการส่วนกลาง คุณจะต้องระบุค่า android:id
สำหรับองค์ประกอบ <navigation>
รูท ดังที่แสดงในตัวอย่างต่อไปนี้
<?xml version="1.0" encoding="utf-8"?> <navigation xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/main_nav" app:startDestination="@id/mainFragment"> ... </navigation>
การนําทางจะสร้างคลาส Directions
สําหรับองค์ประกอบ <navigation>
โดยอิงตามค่า android:id
เช่น หากคุณมีองค์ประกอบ <navigation>
ที่มี android:id=@+id/main_nav
คลาสที่สร้างขึ้นจะเรียกว่า MainNavDirections
ปลายทางทั้งหมดภายในองค์ประกอบ <navigation>
จะมีเมธอดที่สร้างขึ้นสําหรับการเข้าถึงการดําเนินการส่วนกลางที่เกี่ยวข้องทั้งหมดโดยใช้เมธอดเดียวกันตามที่อธิบายไว้ในส่วนก่อนหน้า
ส่งข้อมูลระหว่างปลายทางด้วยออบเจ็กต์ Bundle
หากไม่ได้ใช้ Gradle คุณจะยังคงส่งอาร์กิวเมนต์ระหว่างปลายทางได้โดยใช้ออบเจ็กต์ Bundle
สร้างออบเจ็กต์ Bundle
และส่งไปยังปลายทางโดยใช้ navigate()
ดังตัวอย่างต่อไปนี้
Kotlin
val bundle = bundleOf("amount" to amount) view.findNavController().navigate(R.id.confirmationAction, bundle)
Java
Bundle bundle = new Bundle(); bundle.putString("amount", amount); Navigation.findNavController(view).navigate(R.id.confirmationAction, bundle);
ในโค้ดของปลายทางที่รับ ให้ใช้เมธอด getArguments()
เพื่อดึงข้อมูล Bundle
และใช้เนื้อหา
Kotlin
val tv = view.findViewById<TextView>(R.id.textViewAmount) tv.text = arguments?.getString("amount")
Java
TextView tv = view.findViewById(R.id.textViewAmount); tv.setText(getArguments().getString("amount"));
ส่งข้อมูลไปยังปลายทางเริ่มต้น
คุณสามารถส่งข้อมูลไปยังปลายทางเริ่มต้นของแอป ก่อนอื่น คุณต้องสร้าง Bundle
ที่เก็บข้อมูลอย่างชัดเจน ถัดไป ให้ใช้แนวทางใดแนวทางหนึ่งต่อไปนี้เพื่อส่ง Bundle
ไปยังปลายทางเริ่มต้น
- หากสร้าง
NavHost
โดยใช้โปรแกรม ให้เรียกใช้NavHostFragment.create(R.navigation.graph, args)
โดยที่args
คือBundle
ที่เก็บข้อมูลของคุณ - หรือจะตั้งค่าอาร์กิวเมนต์ปลายทางเริ่มต้นโดยเรียกใช้
NavController.setGraph()
แบบโอเวอร์โหลดรายการใดรายการหนึ่งต่อไปนี้ก็ได้- ใช้รหัสของกราฟ:
navController.setGraph(R.navigation.graph, args)
- ใช้กราฟโดยตรง:
navController.setGraph(navGraph, args)
- ใช้รหัสของกราฟ:
หากต้องการเรียกข้อมูลในปลายทางเริ่มต้น ให้เรียกใช้ Fragment.getArguments()
ข้อควรพิจารณาเกี่ยวกับ ProGuard
หากลดขนาดโค้ด คุณต้องป้องกันไม่ให้ชื่อคลาส Parcelable
, Serializable
และ Enum
ได้รับการสร้างความสับสนในกระบวนการลดขนาด คุณสามารถทำได้ด้วยวิธีใดวิธีหนึ่งใน 2 วิธีต่อไปนี้
- ใช้คำอธิบายประกอบ @Keep
- ใช้กฎ keepnames
ส่วนย่อยต่อไปนี้จะอธิบายแนวทางเหล่านี้
ใช้คำอธิบายประกอบ @Keep
ตัวอย่างต่อไปนี้จะเพิ่มคำอธิบายประกอบ @Keep
ลงในคำจำกัดความของคลาสโมเดล
Kotlin
@Keep class ParcelableArg : Parcelable { ... } @Keep class SerializableArg : Serializable { ... } @Keep enum class EnumArg { ... }
Java
@Keep public class ParcelableArg implements Parcelable { ... } @Keep public class SerializableArg implements Serializable { ... } @Keep public enum EnumArg { ... }
ใช้กฎ keepnames
นอกจากนี้ คุณยังเพิ่มกฎ keepnames
ลงในไฟล์ proguard-rules.pro
ได้ด้วย ดังที่แสดงในตัวอย่างต่อไปนี้
proguard-rules.pro
...
-keepnames class com.path.to.your.ParcelableArg
-keepnames class com.path.to.your.SerializableArg
-keepnames class com.path.to.your.EnumArg
...
แหล่งข้อมูลเพิ่มเติม
ดูข้อมูลเพิ่มเติมเกี่ยวกับการนําทางได้จากแหล่งข้อมูลเพิ่มเติมต่อไปนี้