ส่งข้อมูลระหว่างจุดหมาย

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

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

กำหนดอาร์กิวเมนต์ปลายทาง

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

  1. ในเครื่องมือแก้ไขการนําทาง ให้คลิกปลายทางที่รับอาร์กิวเมนต์
  2. ในแผงแอตทริบิวต์ ให้คลิกเพิ่ม (+)
  3. ในหน้าต่างเพิ่มลิงก์อาร์กิวเมนต์ที่ปรากฏขึ้น ให้ป้อนชื่ออาร์กิวเมนต์ ประเภทอาร์กิวเมนต์ ระบุว่าอาร์กิวเมนต์เป็นค่าที่อนุญาตหรือไม่ และค่าเริ่มต้น หากจำเป็น
  4. คลิกเพิ่ม โปรดทราบว่าตอนนี้อาร์กิวเมนต์จะปรากฏในรายการอาร์กิวเมนต์ในแผงแอตทริบิวต์
  5. จากนั้นคลิกการดําเนินการที่เกี่ยวข้องซึ่งนําคุณไปยังปลายทางนี้ ในแผงแอตทริบิวต์ คุณควรเห็นอาร์กิวเมนต์ที่เพิ่มใหม่ในส่วนค่าเริ่มต้นของอาร์กิวเมนต์
  6. นอกจากนี้ คุณยังเห็นว่ามีการเพิ่มอาร์กิวเมนต์ใน 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 เพื่อส่งผ่านข้อมูลได้โดยตรง

To add Safe Args to your project, include the following classpath in your top level build.gradle file:

Groovy

buildscript {
    repositories {
        google()
    }
    dependencies {
        def nav_version = "2.8.9"
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
    }
}

Kotlin

buildscript {
    repositories {
        google()
    }
    dependencies {
        val nav_version = "2.8.9"
        classpath("androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version")
    }
}

You must also apply one of two available plugins.

To generate Java language code suitable for Java or mixed Java and Kotlin modules, add this line to your app or module's build.gradle file:

Groovy

plugins {
  id 'androidx.navigation.safeargs'
}

Kotlin

plugins {
    id("androidx.navigation.safeargs")
}

Alternatively, to generate Kotlin code suitable for Kotlin-only modules add:

Groovy

plugins {
  id 'androidx.navigation.safeargs.kotlin'
}

Kotlin

plugins {
    id("androidx.navigation.safeargs.kotlin")
}

You must have android.useAndroidX=true in your gradle.properties file as per Migrating to 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() แบบโอเวอร์โหลดรายการใดรายการหนึ่งต่อไปนี้ก็ได้

หากต้องการเรียกข้อมูลในปลายทางเริ่มต้น ให้เรียกใช้ 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

...

แหล่งข้อมูลเพิ่มเติม

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

Codelabs

วิดีโอ