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

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

โดยทั่วไปแล้ว คุณควรส่งข้อมูลในปริมาณน้อยที่สุด ระหว่างปลายทาง เช่น คุณควรส่งคีย์เพื่อเรียกข้อมูลออบเจ็กต์ แทนที่จะส่งตัวอ็อบเจกต์ เพราะเป็นพื้นที่รวมสำหรับสถานะที่บันทึกไว้ทั้งหมด ถูกจำกัดใน Android ถ้าคุณต้องการส่งผ่านข้อมูลปริมาณมาก ให้ใช้ 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:ARPType="integer" ใช่ ได้ ไม่
ล่องลอย app:argType="Flo" ใช่ ได้ ไม่
ยาว app:ARPType="long" ใช่ - ค่าเริ่มต้นต้องลงท้ายด้วย "L" เสมอ คำต่อท้าย (เช่น "123L") ใช่ ไม่
บูลีน app:ARPType="boolean" ใช่ - "จริง" หรือ "เท็จ" ใช่ ไม่
สตริง app:argType="string" ใช่ ได้ ใช่
การอ้างอิงทรัพยากร app:argType="reference" ใช่ ค่าเริ่มต้นต้องอยู่ในรูปแบบ "@resourceType/resourceName" (เช่น "@style/myCustomStyle") หรือ "0" ใช่ ไม่
พาร์เซลที่กำหนดเอง app:argType="<type>" โดยที่ <type> คือชื่อคลาสที่มีคุณสมบัติครบถ้วนของ Parcelable รองรับค่าเริ่มต้นเป็น "@null" ไม่รองรับค่าเริ่มต้นอื่นๆ ไม่ ใช่
ซีเรียลได้แบบกำหนดเอง app:argType="<type>" โดยที่ <type> คือชื่อคลาสที่มีคุณสมบัติครบถ้วนของ Serializable รองรับค่าเริ่มต้นเป็น "@null" ไม่รองรับค่าเริ่มต้นอื่นๆ ไม่ ใช่
Enum ที่กำหนดเอง app:argType="<type>" โดยที่ <type> คือชื่อที่มีคุณสมบัติครบถ้วนของ enum ใช่ - ค่าเริ่มต้นต้องตรงกับชื่อที่ไม่เข้าเกณฑ์ (เช่น "สำเร็จ" เพื่อให้ตรงกับ MyEnum.SUCCESS) ไม่ ไม่

ถ้าประเภทอาร์กิวเมนต์รองรับค่า Null คุณจะประกาศค่าเริ่มต้นได้ null โดยใช้ android:defaultValue="@null"

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

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

คุณสามารถเลือก <inferred type> ให้มีไลบรารีการนำทาง กำหนดประเภทตามค่าที่ระบุ

คุณสามารถตรวจสอบ Array เพื่อระบุว่าอาร์กิวเมนต์ควรเป็นอาร์เรย์ของ ค่า Type ที่เลือกไว้ ข้อควรทราบ

  • ระบบไม่รองรับอาร์เรย์ของ enum และอาร์เรย์ของการอ้างอิงทรัพยากร
  • อาร์เรย์รองรับค่า Nullable โดยไม่คำนึงถึงการรองรับค่า 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>

ใช้ Args ที่ปลอดภัยเพื่อส่งผ่านข้อมูลด้วยประเภทความปลอดภัย

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

หากไม่ได้ใช้ Gradle คุณจะใช้ Gradle ไม่ได้ ปลั๊กอิน Args ในกรณีเหล่านี้ คุณใช้แพ็กเกจได้โดยตรง ส่งข้อมูล

วิธีเพิ่ม อาร์กิวเมนต์ที่ปลอดภัย ลงในโปรเจ็กต์ของคุณ ให้ใส่ classpath ต่อไปนี้ในไฟล์ build.gradle ระดับบนสุด

ดึงดูด

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

Kotlin

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

นอกจากนี้ คุณต้องใช้ปลั๊กอิน 1 ใน 2 รายการที่มีอยู่ด้วย

หากต้องการสร้างโค้ดภาษา Java ที่เหมาะสำหรับโมดูล Java และ Kotlin แบบผสม ให้เพิ่ม บรรทัดนี้ไปยังไฟล์ build.gradle ของแอปหรือโมดูลของคุณ

ดึงดูด

plugins {
  id 'androidx.navigation.safeargs'
}

Kotlin

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

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

ดึงดูด

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() เพื่อเรียกแพ็กเกจและใช้เนื้อหาของแพ็กเกจ เมื่อใช้ทรัพยากร Dependency -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 กับ การดำเนินการส่วนกลาง คุณต้องระบุค่า 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 ให้ยากต่อการอ่าน (Obfuscate) เพื่อเป็นส่วนหนึ่งของ กระบวนการลดขนาด คุณสามารถทำได้ด้วยวิธีใดวิธีหนึ่งใน 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 { ... }

ใช้กฎ Keepname

คุณยังเพิ่มกฎ 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

...

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

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

ตัวอย่าง

Codelab

วิดีโอ