ย้ายข้อมูลไปยังคอมโพเนนต์การนำทาง

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

เอกสารนี้ทำหน้าที่เป็นคำแนะนำทั่วไปในการย้ายข้อมูลแอปที่มีอยู่ไปยัง ใช้คอมโพเนนต์การนำทาง

ในระดับสูง การย้ายข้อมูลจะเกี่ยวข้องกับขั้นตอนเหล่านี้

  1. ย้ายตรรกะ UI เฉพาะหน้าจอออกจากกิจกรรม - ย้าย UI ของแอป ออกจากกิจกรรมเพื่อให้แน่ใจว่าแต่ละกิจกรรมเป็นเจ้าของเฉพาะตรรกะของ คอมโพเนนต์ UI การนำทางส่วนกลาง เช่น Toolbar ในขณะที่มอบสิทธิ์ การนำแต่ละหน้าจอมาติดตั้งในส่วนย่อยหรือปลายทางที่กำหนดเอง

  2. ผสานรวมคอมโพเนนต์การนำทาง - สำหรับแต่ละกิจกรรม ให้สร้าง กราฟการนำทางซึ่งมีส่วนย่อยอย่างน้อย 1 รายการที่จัดการโดย กิจกรรม แทนที่ธุรกรรมส่วนย่อยด้วยการดำเนินการของคอมโพเนนต์การนำทาง

  3. เพิ่มจุดหมายของกิจกรรม - แทนที่สาย startActivity() ด้วย โดยใช้ปลายทางกิจกรรม

  4. รวมกิจกรรม - รวมกราฟการนำทางในกรณีที่ กิจกรรมหลายอย่างจะใช้เลย์เอาต์เดียวกัน

สิ่งที่ต้องมีก่อน

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

ย้ายตรรกะ UI เฉพาะหน้าจอออกจากกิจกรรม

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

กิจกรรมควรทำหน้าที่เป็นโฮสต์สำหรับการนำทางในบริบทของแอป และควรมีตรรกะและความรู้เกี่ยวกับวิธีการเปลี่ยนหน้าจอ ส่งข้อมูล และอื่นๆ อย่างไรก็ตาม คุณควรจัดการรายละเอียดของ UI ได้ง่ายกว่า ให้มีขนาดเล็กลงและใช้ซ้ำได้ การติดตั้งใช้งานที่แนะนำสำหรับ รูปแบบคือส่วนย่อย โปรดดู กิจกรรมเดียว: ทำไม เวลา และอย่างไร เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับข้อดีของการใช้ Fragment การนำทางรองรับส่วนย่อยผ่านทรัพยากร Dependency ของ navigation-อื่นๆ การนำทางยังรองรับ ประเภทปลายทางที่กำหนดเอง

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

ขอแนะนำ Fragment

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

ในตัวอย่างนี้ หน้าจอรายการและหน้าจอรายละเอียดเป็นกิจกรรมที่แยกกันในปัจจุบัน

สร้างเลย์เอาต์ใหม่เพื่อโฮสต์ UI

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

หากต้องการดูมุมมองอย่างง่าย คุณสามารถใช้ FrameLayout ได้ ดังที่แสดงใน ตัวอย่าง product_list_host:

<FrameLayout
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:id="@+id/main_content"
   android:layout_height="match_parent"
   android:layout_width="match_parent" />

แอตทริบิวต์ id คือส่วนเนื้อหาที่เราจะเพิ่ม ส่วนย่อย

ถัดไป แก้ไขการอ้างอิงไฟล์เลย์เอาต์ในฟังก์ชัน onCreate() ของกิจกรรม ในฟังก์ชัน onCreate ของกิจกรรมให้ชี้ไปยังไฟล์เลย์เอาต์ใหม่นี้

Kotlin

class ProductListActivity : AppCompatActivity() {
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        // Replace setContentView(R.layout.product_list) with the line below
        setContentView(R.layout.product_list_host)
        ...
    }
}

Java

public class ProductListActivity extends AppCompatActivity {
    ...
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        ...
        // Replace setContentView(R.layout.product_list); with the line below
        setContentView(R.layout.product_list_host);
        ...
    }
}

การออกแบบที่มีอยู่ (ในตัวอย่างนี้คือ product_list) จะใช้เป็นมุมมองรูท สำหรับส่วนย่อยที่คุณกำลังจะสร้าง

สร้างส่วนย่อย

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

Kotlin

class ProductListFragment : Fragment() {
    // Leave empty for now.
}

Java

public class ProductListFragment extends Fragment {
    // Leave empty for now.
}

ย้ายตรรกะกิจกรรมไปไว้ในส่วนย่อย

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

ต่อไปนี้คือตัวอย่างหน้าจอตามกิจกรรมที่มีตรรกะ UI ที่เราต้องย้าย

Kotlin

class ProductListActivity : AppCompatActivity() {

    // Views and/or ViewDataBinding references, Adapters...
    private lateinit var productAdapter: ProductAdapter
    private lateinit var binding: ProductListActivityBinding

    ...

    // ViewModels, System Services, other Dependencies...
    private val viewModel: ProductListViewModel by viewModels()

    ...

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // View initialization logic
        DataBindingUtil.setContentView(this, R.layout.product_list_activity)

        // Post view initialization logic
        // Connect adapters
        productAdapter = ProductAdapter(productClickCallback)
        binding.productsList.setAdapter(productAdapter)

        // Initialize view properties, set click listeners, etc.
        binding.productsSearchBtn.setOnClickListener {...}

        // Subscribe to state
        viewModel.products.observe(this, Observer { myProducts ->
            ...
        })

        // ...and so on
    }
   ...
}

Java

public class ProductListActivity extends AppCompatActivity {

    // Views and/or ViewDataBinding references, adapters...
    private ProductAdapter productAdapter;
    private ProductListActivityBinding binding;

    ...

    // ViewModels, system services, other dependencies...
    private ProductListViewModel viewModel;

    ...

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // View initialization logic
        DataBindingUtil.setContentView(this, R.layout.product_list_activity);

        // Post view initialization logic
        // Connect adapters
        productAdapter = new ProductAdapter(productClickCallback);
        binding.productsList.setAdapter(productAdapter);

        // Initialize ViewModels and other dependencies
        ProductListViewModel viewModel = new ViewModelProvider(this).get(ProductListViewModel.java);

        // Initialize view properties, set click listeners, etc.
        binding.productsSearchBtn.setOnClickListener(v -> { ... });

        // Subscribe to state
        viewModel.getProducts().observe(this, myProducts ->
            ...
       );

       // ...and so on
   }

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

Kotlin

    // Provided to ProductAdapter in ProductListActivity snippet.
    private val productClickCallback = ProductClickCallback { product ->
        show(product)
    }

    fun show(product: Product) {
        val intent = Intent(this, ProductActivity::class.java)
        intent.putExtra(ProductActivity.KEY_PRODUCT_ID, product.id)
        startActivity(intent)
    }

Java

// Provided to ProductAdapter in ProductListActivity snippet.
private ProductClickCallback productClickCallback = this::show;

private void show(Product product) {
    Intent intent = new Intent(this, ProductActivity.class);
    intent.putExtra(ProductActivity.KEY_PRODUCT_ID, product.getId());
    startActivity(intent);
}

ภายในส่วนย่อยของคุณ คุณกระจายงานนี้ระหว่าง onCreateView() และ onViewCreated(), โดยใช้ตรรกะการนำทางเหลืออยู่ในกิจกรรมเท่านั้น

Kotlin

class ProductListFragment : Fragment() {

    private lateinit var binding: ProductListFragmentBinding
    private val viewModel: ProductListViewModel by viewModels()

     // View initialization logic
    override fun onCreateView(inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?): View? {
        binding = DataBindingUtil.inflate(
                inflater,
                R.layout.product_list,
                container,
                false
        )
        return binding.root
    }

    // Post view initialization logic
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        // Connect adapters
        productAdapter = ProductAdapter(productClickCallback)
        binding.productsList.setAdapter(productAdapter)

        // Initialize view properties, set click listeners, etc.
        binding.productsSearchBtn.setOnClickListener {...}

        // Subscribe to state
        viewModel.products.observe(this, Observer { myProducts ->
            ...
        })

        // ...and so on
    }

    // Provided to ProductAdapter
    private val productClickCallback = ProductClickCallback { product ->
        if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
            (requireActivity() as ProductListActivity).show(product)
        }
    }
    ...
}

Java

public class ProductListFragment extends Fragment {

    private ProductAdapter productAdapter;
    private ProductListFragmentBinding binding;

    // View initialization logic
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater,
            @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        binding = DataBindingUtil.inflate(
                inflater,
                R.layout.product_list_fragment,
                container,
                false);
        return binding.getRoot();
    }

    // Post view initialization logic
    @Override
    public void onViewCreated(@NonNull View view,
            @Nullable Bundle savedInstanceState) {

        // Connect adapters
        binding.productsList.setAdapter(productAdapter);

        // Initialize ViewModels and other dependencies
        ProductListViewModel viewModel = new ViewModelProvider(this)
                .get(ProductListViewModel.class);

        // Initialize view properties, set click listeners, etc.
        binding.productsSearchBtn.setOnClickListener(...)

        // Subscribe to state
        viewModel.getProducts().observe(this, myProducts -> {
            ...
       });

       // ...and so on

    // Provided to ProductAdapter
    private ProductClickCallback productClickCallback = new ProductClickCallback() {
        @Override
        public void onClick(Product product) {
            if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
                ((ProductListActivity) requireActivity()).show(product);
            }
        }
    };
    ...
}

ใน ProductListFragment สังเกตว่าไม่มีการเรียก setContentView() เพื่อขยายและเชื่อมต่อเลย์เอาต์ ในส่วนย่อย onCreateView() จะเริ่มต้น มุมมองระดับรูท onCreateView() อินสแตนซ์ของ LayoutInflater ซึ่งสามารถใช้เพื่อ ขยายมุมมองรูทตามไฟล์ทรัพยากรของเลย์เอาต์ ตัวอย่างนี้ใช้ เลย์เอาต์ product_list ที่มีอยู่ซึ่งกิจกรรมใช้เนื่องจากไม่มีรายการใด ก็จำเป็นต้องเปลี่ยนเป็น เลย์เอาต์นั้นเอง

หากมีตรรกะ UI อยู่ใน onStart() onResume() ของกิจกรรม ฟังก์ชัน onPause() หรือ onStop() ที่ไม่เกี่ยวข้องกับการนำทาง คุณสามารถ ให้ย้ายฟังก์ชันเหล่านั้นไปยังฟังก์ชันที่มีชื่อเดียวกันบนส่วนย่อย

เริ่มต้นส่วนย่อยในกิจกรรมโฮสต์

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

Kotlin

class ProductListActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.product_list_host)
    }

    fun show(product: Product) {
        val intent = Intent(this, ProductActivity::class.java)
        intent.putExtra(ProductActivity.KEY_PRODUCT_ID, product.id)
        startActivity(intent)
    }
}

Java

public class ProductListActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.product_list_host);
    }

    public void show(Product product) {
        Intent intent = new Intent(this, ProductActivity.class);
        intent.putExtra(ProductActivity.KEY_PRODUCT_ID, product.getId());
        startActivity(intent);
    }
}

ขั้นตอนสุดท้ายคือการสร้างอินสแตนซ์ของส่วนย่อยใน onCreate() จากนั้น หลังจากตั้งค่ามุมมองเนื้อหา

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.product_list_host)

    if (savedInstanceState == null) {
        val fragment = ProductListFragment()
        supportFragmentManager
                .beginTransaction()
                .add(R.id.main_content, fragment)
                .commit()
    }
}

Java

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.product_list_host);

    if (savedInstanceState == null) {
        ProductListFragment fragment = new ProductListFragment();
        getSupportFragmentManager()
                .beginTransaction()
                .add(R.id.main_content, fragment)
                .commit();
    }
}

ดังที่แสดงในตัวอย่างนี้ FragmentManager จะบันทึกและคืนค่าโดยอัตโนมัติ ส่วนย่อยในการเปลี่ยนแปลงการกำหนดค่า คุณจึงต้องเพิ่มส่วนย่อยก็ต่อเมื่อ savedInstanceState เป็นค่าว่าง

ส่งต่อ Intent เพิ่มเติมไปยังส่วนย่อย

หากกิจกรรมได้รับ Extras ผ่านทาง Intent คุณสามารถส่งรายการเหล่านี้ไปยัง เป็นอาร์กิวเมนต์โดยตรง

ในตัวอย่างนี้ ProductDetailsFragment ได้รับอาร์กิวเมนต์โดยตรง จาก Intent เพิ่มเติมของกิจกรรม

Kotlin

...

if (savedInstanceState == null) {
    val fragment = ProductDetailsFragment()

    // Intent extras and Fragment Args are both of type android.os.Bundle.
    fragment.arguments = intent.extras

    supportFragmentManager
            .beginTransaction()
            .add(R.id.main_content, fragment)
            .commit()
}

...

Java

...

if (savedInstanceState == null) {
    ProductDetailsFragment fragment = new ProductDetailsFragment();

    // Intent extras and fragment Args are both of type android.os.Bundle.
    fragment.setArguments(getIntent().getExtras());

    getSupportFragmentManager()
            .beginTransaction()
            .add(R.id.main_content, fragment)
            .commit();
}

...

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

ผสานรวมคอมโพเนนต์การนำทาง

เมื่อใช้สถาปัตยกรรมที่อิงตามส่วนย่อย คุณก็พร้อมที่จะเริ่มผสานรวมคอมโพเนนต์การนำทางแล้ว

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

สร้างกราฟการนำทาง

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

หากต้องการสร้างกราฟการนำทาง ให้เริ่มต้นด้วยการสร้างโฟลเดอร์ทรัพยากรใหม่ชื่อ navigation ในการเพิ่มกราฟ ให้คลิกขวาที่ไดเรกทอรีนี้ และเลือก ใหม่ > ไฟล์ทรัพยากรการนำทาง

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

NavHostFragment ได้รับการกำหนดค่าผ่าน FragmentContainerView วางไว้ภายในกิจกรรมของโฮสต์ ดังที่แสดงในตัวอย่างต่อไปนี้

<androidx.fragment.app.FragmentContainerView
   android:name="androidx.navigation.fragment.NavHostFragment"
   app:navGraph="@navigation/product_list_graph"
   app:defaultNavHost="true"
   android:id="@+id/main_content"
   android:layout_width="match_parent"
   android:layout_height="match_parent" />

แอตทริบิวต์ app:NavGraph ชี้ไปยังกราฟการนำทางที่เกี่ยวข้องกับ โฮสต์การนำทาง การตั้งค่าคุณสมบัตินี้จะขยายกราฟการนำทางและตั้งค่ากราฟ ใน NavHostFragment แอตทริบิวต์ app:defaultNavHost จะช่วยให้มั่นใจได้ว่า ว่า NavHostFragment ดักจับปุ่ม "ย้อนกลับ" ของระบบ

หากคุณใช้การนำทางระดับบนสุด เช่น DrawerLayout หรือ BottomNavigationView, FragmentContainerViewนี้ จะแทนที่องค์ประกอบมุมมองเนื้อหาหลักของคุณ โปรดดู อัปเดตคอมโพเนนต์ UI ด้วย NavigationUI เพื่อดูตัวอย่าง

สำหรับเลย์เอาต์ที่เรียบง่าย คุณสามารถรวม FragmentContainerView นี้ เป็นองค์ประกอบย่อยของราก ViewGroup:

<FrameLayout
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_height="match_parent"
   android:layout_width="match_parent">

<androidx.fragment.app.FragmentContainerView
   android:id="@+id/main_content"
   android:name="androidx.navigation.fragment.NavHostFragment"
   app:navGraph="@navigation/product_list_graph"
   app:defaultNavHost="true"
   android:layout_width="match_parent"
   android:layout_height="match_parent" />

</FrameLayout>

หากคุณคลิกแท็บการออกแบบที่ด้านล่าง คุณจะเห็นกราฟ กับรายการที่แสดงด้านล่าง ที่ด้านซ้ายบนของกราฟ ใต้ ปลายทางคุณสามารถดูการอ้างอิงถึงกิจกรรม NavHost ได้ในแบบฟอร์ม จาก layout_name (resource_id)

คลิกปุ่มบวก ใกล้กับด้านบนเพื่อเพิ่มส่วนย่อยลงในกราฟนี้

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

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

นำธุรกรรมส่วนย่อยออก

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

หากแอปใช้ Fragment หลายรายการในกิจกรรมเดียวกันหรือระดับบนสุด เช่น เลย์เอาต์ลิ้นชักหรือการนำทางด้านล่าง โดยใช้ FragmentManager และ FragmentTransactions เพื่อเพิ่มหรือแทนที่ส่วนย่อยในส่วนเนื้อหาหลักของ UI การดำเนินการนี้สามารถ แทนและทำให้ง่ายขึ้นด้วยคอมโพเนนต์การนำทางโดยแสดงการทำงาน เพื่อลิงก์ปลายทางภายในกราฟ แล้วนำทางโดยใช้ NavController

ต่อไปนี้คือสถานการณ์ที่คุณอาจพบ พร้อมกับวิธีดำเนินการ สำหรับแต่ละสถานการณ์

กิจกรรมเดียวที่จัดการส่วนย่อยหลายรายการ

หากคุณมีกิจกรรมเดียวที่จัดการส่วนย่อยหลายรายการ กิจกรรมของคุณ โค้ดอาจมีลักษณะเช่นนี้

Kotlin

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Logic to load the starting destination
        //  when the Activity is first created
        if (savedInstanceState == null) {
            val fragment = ProductListFragment()
            supportFragmentManager.beginTransaction()
                    .add(R.id.fragment_container, fragment, ProductListFragment.TAG)
                    .commit()
        }
    }

    // Logic to navigate the user to another destination.
    // This may include logic to initialize and set arguments on the destination
    // fragment or even transition animations between the fragments (not shown here).
    fun navigateToProductDetail(productId: String) {
        val fragment = new ProductDetailsFragment()
        val args = Bundle().apply {
            putInt(KEY_PRODUCT_ID, productId)
        }
        fragment.arguments = args

        supportFragmentManager.beginTransaction()
                .addToBackStack(ProductDetailsFragment.TAG)
                .replace(R.id.fragment_container, fragment, ProductDetailsFragment.TAG)
                .commit()
    }
}

Java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Logic to load the starting destination when the activity is first created.
        if (savedInstanceState == null) {
            val fragment = ProductListFragment()
            supportFragmentManager.beginTransaction()
                    .add(R.id.fragment_container, fragment, ProductListFragment.TAG)
                    .commit();
        }
    }

    // Logic to navigate the user to another destination.
    // This may include logic to initialize and set arguments on the destination
    // fragment or even transition animations between the fragments (not shown here).
    public void navigateToProductDetail(String productId) {
        Fragment fragment = new ProductDetailsFragment();
        Bundle args = new Bundle();
        args.putInt(KEY_PRODUCT_ID, productId);
        fragment.setArguments(args);

        getSupportFragmentManager().beginTransaction()
                .addToBackStack(ProductDetailsFragment.TAG)
                .replace(R.id.fragment_container, fragment, ProductDetailsFragment.TAG)
                .commit();
    }
}

ภายในปลายทางต้นทาง คุณอาจเรียกใช้ฟังก์ชันการนำทางใน การตอบกลับบางกิจกรรมดังที่แสดงด้านล่าง

Kotlin

class ProductListFragment : Fragment() {
    ...
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        // In this example a callback is passed to respond to an item clicked
        //  in a RecyclerView
        productAdapter = ProductAdapter(productClickCallback)
        binding.productsList.setAdapter(productAdapter)
    }
    ...

    // The callback makes the call to the activity to make the transition.
    private val productClickCallback = ProductClickCallback { product ->
            (requireActivity() as MainActivity).navigateToProductDetail(product.id)
    }
}

Java

public class ProductListFragment extends Fragment  {
    ...
    @Override
    public void onViewCreated(@NonNull View view,
            @Nullable Bundle savedInstanceState) {
    // In this example a callback is passed to respond to an item clicked in a RecyclerView
        productAdapter = new ProductAdapter(productClickCallback);
        binding.productsList.setAdapter(productAdapter);
    }
    ...

    // The callback makes the call to the activity to make the transition.
    private ProductClickCallback productClickCallback = product -> (
        ((MainActivity) requireActivity()).navigateToProductDetail(product.getId())
    );
}

ซึ่งสามารถแทนที่โดยการอัปเดตกราฟการนำทางเพื่อกำหนด ปลายทางเริ่มต้นและการดำเนินการเพื่อลิงก์ปลายทางและกำหนด อาร์กิวเมนต์ที่จำเป็น

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/product_list_graph"
    app:startDestination="@id/product_list">

    <fragment
        android:id="@+id/product_list"
        android:name="com.example.android.persistence.ui.ProductListFragment"
        android:label="Product List"
        tools:layout="@layout/product_list">
        <action
            android:id="@+id/navigate_to_product_detail"
            app:destination="@id/product_detail" />
    </fragment>
    <fragment
        android:id="@+id/product_detail"
        android:name="com.example.android.persistence.ui.ProductDetailFragment"
        android:label="Product Detail"
        tools:layout="@layout/product_detail">
        <argument
            android:name="product_id"
            app:argType="integer" />
    </fragment>
</navigation>

จากนั้นคุณจะอัปเดตกิจกรรมได้โดยทำดังนี้

Kotlin

class MainActivity : AppCompatActivity() {

    // No need to load the start destination, handled automatically by the Navigation component
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

Java

public class MainActivity extends AppCompatActivity {

    // No need to load the start destination, handled automatically by the Navigation component
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

กิจกรรมไม่ต้องใช้เมธอด navigateToProductDetail() แล้ว ในอีก เราจะอัปเดต ProductListFragment เพื่อใช้ NavController ในการนำทาง ไปยังหน้าจอรายละเอียดผลิตภัณฑ์ถัดไป

ส่งต่ออาร์กิวเมนต์อย่างปลอดภัย

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

เมื่อใช้ปลั๊กอินแล้ว อาร์กิวเมนต์ใดก็ตามที่กำหนดไว้ในปลายทางใน กราฟการนำทางทำให้เฟรมเวิร์กคอมโพเนนต์การนำทางสร้าง คลาส Arguments ที่ระบุอาร์กิวเมนต์ที่ปลอดภัยตามประเภทในปลายทางเป้าหมาย การกำหนดการดำเนินการจะทำให้ปลั๊กอินสร้างการกำหนดค่า Directions ซึ่งสามารถใช้บอก NavController เกี่ยวกับวิธีนำทางผู้ใช้ไปยัง ปลายทาง เมื่อการดำเนินการชี้ไปยังปลายทางที่จำเป็นต้องใช้ อาร์กิวเมนต์ คลาส Directions ที่สร้างขึ้นจะมี Method ของตัวสร้าง ซึ่งจำเป็นต้องใช้พารามิเตอร์เหล่านั้น

ภายในส่วนย่อย ให้ใช้ NavController และคลาส Directions ที่สร้างขึ้นเพื่อ จะระบุอาร์กิวเมนต์ type-safe กับปลายทางเป้าหมาย ดังที่ปรากฏใน ตัวอย่าง:

Kotlin

class ProductListFragment : Fragment() {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        // In this example a callback is passed to respond to an item clicked in a RecyclerView
        productAdapter = ProductAdapter(productClickCallback)
        binding.productsList.setAdapter(productAdapter)
    }
    ...

    // The callback makes the call to the NavController to make the transition.
    private val productClickCallback = ProductClickCallback { product ->
        val directions = ProductListDirections.navigateToProductDetail(product.id)
        findNavController().navigate(directions)
    }
}

Java

public class ProductListFragment extends Fragment  {
    ...
    @Override
    public void onViewCreated(@NonNull View view,
            @Nullable Bundle savedInstanceState) {
        // In this example a callback is passed to respond to an item clicked in a RecyclerView
        productAdapter = new ProductAdapter(productClickCallback);
        binding.productsList.setAdapter(productAdapter);
    }
    ...

    // The callback makes the call to the activity to make the transition.
    private ProductClickCallback productClickCallback = product -> {
        ProductListDirections.ViewProductDetails directions =
                ProductListDirections.navigateToProductDetail(product.getId());
        NavHostFragment.findNavController(this).navigate(directions);
    };
}

การนำทางระดับบนสุด

หากแอปใช้ DrawerLayout คุณอาจมีตรรกะการกำหนดค่าจำนวนมาก ในกิจกรรมที่จัดการการเปิดและปิดลิ้นชัก และไปยัง ปลายทางอื่นๆ

กิจกรรมที่เป็นผลลัพธ์อาจมีลักษณะดังนี้

Kotlin

class MainActivity : AppCompatActivity(),
    NavigationView.OnNavigationItemSelectedListener {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val toolbar: Toolbar = findViewById(R.id.toolbar)
        setSupportActionBar(toolbar)

        val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
        val navView: NavigationView = findViewById(R.id.nav_view)
        val toggle = ActionBarDrawerToggle(
                this,
                drawerLayout,
                toolbar,
                R.string.navigation_drawer_open, 
                R.string.navigation_drawer_close
        )
        drawerLayout.addDrawerListener(toggle)
        toggle.syncState()

        navView.setNavigationItemSelectedListener(this)
    }

    override fun onBackPressed() {
        val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
        if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
            drawerLayout.closeDrawer(GravityCompat.START)
        } else {
            super.onBackPressed()
        }
    }

    override fun onNavigationItemSelected(item: MenuItem): Boolean {
        // Handle navigation view item clicks here.
        when (item.itemId) {
            R.id.home -> {
                val homeFragment = HomeFragment()
                show(homeFragment)
            }
            R.id.gallery -> {
                val galleryFragment = GalleryFragment()
                show(galleryFragment)
            }
            R.id.slide_show -> {
                val slideShowFragment = SlideShowFragment()
                show(slideShowFragment)
            }
            R.id.tools -> {
                val toolsFragment = ToolsFragment()
                show(toolsFragment)
            }
        }
        val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
        drawerLayout.closeDrawer(GravityCompat.START)
        return true
    }
}

private fun show(fragment: Fragment) {

    val drawerLayout = drawer_layout as DrawerLayout
    val fragmentManager = supportFragmentManager

    fragmentManager
            .beginTransaction()
            .replace(R.id.main_content, fragment)
            .commit()

    drawerLayout.closeDrawer(GravityCompat.START)
}

Java

public class MainActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        DrawerLayout drawer = findViewById(R.id.drawer_layout);
        NavigationView navigationView = findViewById(R.id.nav_view);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this,
                drawer,
                toolbar,
                R.string.navigation_drawer_open,
                R.string.navigation_drawer_close);
        drawer.addDrawerListener(toggle);
        toggle.syncState();

        navigationView.setNavigationItemSelectedListener(this);
    }

    @Override
    public void onBackPressed() {
        DrawerLayout drawer = findViewById(R.id.drawer_layout);
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }

    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        // Handle navigation view item clicks here.
        int id = item.getItemId();

        if (id == R.id.home) {
            Fragment homeFragment = new HomeFragment();
            show(homeFragment);
        } else if (id == R.id.gallery) {
            Fragment galleryFragment = new GalleryFragment();
            show(galleryFragment);
        } else if (id == R.id.slide_show) {
            Fragment slideShowFragment = new SlideShowFragment();
            show(slideShowFragment);
        } else if (id == R.id.tools) {
            Fragment toolsFragment = new ToolsFragment();
            show(toolsFragment);
        }

        DrawerLayout drawer = findViewById(R.id.drawer_layout);
        drawer.closeDrawer(GravityCompat.START);
        return true;
    }

    private void show(Fragment fragment) {

        DrawerLayout drawerLayout = findViewById(R.id.drawer_layout);
        FragmentManager fragmentManager = getSupportFragmentManager();

        fragmentManager
                .beginTransaction()
                .replace(R.id.main_content, fragment)
                .commit();

        drawerLayout.closeDrawer(GravityCompat.START);
    }
}

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

<!-- activity_main_drawer.xml -->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:showIn="navigation_view">

    <group android:checkableBehavior="single">
        <item
            android:id="@+id/home"
            android:icon="@drawable/ic_menu_camera"
            android:title="@string/menu_home" />
        <item
            android:id="@+id/gallery"
            android:icon="@drawable/ic_menu_gallery"
            android:title="@string/menu_gallery" />
        <item
            android:id="@+id/slide_show"
            android:icon="@drawable/ic_menu_slideshow"
            android:title="@string/menu_slideshow" />
        <item
            android:id="@+id/tools"
            android:icon="@drawable/ic_menu_manage"
            android:title="@string/menu_tools" />
    </group>
</menu>
<!-- activity_main_graph.xml -->
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_graph"
    app:startDestination="@id/home">

    <fragment
        android:id="@+id/home"
        android:name="com.example.HomeFragment"
        android:label="Home"
        tools:layout="@layout/home" />

    <fragment
        android:id="@+id/gallery"
        android:name="com.example.GalleryFragment"
        android:label="Gallery"
        tools:layout="@layout/gallery" />

    <fragment
        android:id="@+id/slide_show"
        android:name="com.example.SlideShowFragment"
        android:label="Slide Show"
        tools:layout="@layout/slide_show" />

    <fragment
        android:id="@+id/tools"
        android:name="com.example.ToolsFragment"
        android:label="Tools"
        tools:layout="@layout/tools" />

</navigation>

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

จากนั้นคุณจะอัปเดต MainActivity เพื่อโอน NavController ไปยัง Toolbar และ NavigationView

ดูตัวอย่างต่อไปนี้

Kotlin

class MainActivity : AppCompatActivity()  {

    val drawerLayout by lazy { findViewById<DrawerLayout>(R.id.drawer_layout) }
    val navController by lazy {
      (supportFragmentManager.findFragmentById(R.id.main_content) as NavHostFragment).navController
    }
    val navigationView by lazy { findViewById<NavigationView>(R.id.nav_view) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val toolbar = findViewById<Toolbar>(R.id.toolbar)
        setSupportActionBar(toolbar)

        // Show and Manage the Drawer and Back Icon
        setupActionBarWithNavController(navController, drawerLayout)

        // Handle Navigation item clicks
        // This works with no further action on your part if the menu and destination id’s match.
        navigationView.setupWithNavController(navController)

    }

    override fun onSupportNavigateUp(): Boolean {
        // Allows NavigationUI to support proper up navigation or the drawer layout
        // drawer menu, depending on the situation
        return navController.navigateUp(drawerLayout)
    }
}

Java

public class MainActivity extends AppCompatActivity {

    private DrawerLayout drawerLayout;
    private NavController navController;
    private NavigationView navigationView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        drawerLayout = findViewById(R.id.drawer_layout);
        NavHostFragment navHostFragment = (NavHostFragment)
            getSupportFragmentManager().findFragmentById(R.id.main_content);
        navController = navHostFragment.getNavController();
        navigationView = findViewById(R.id.nav_view);

        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        // Show and Manage the Drawer and Back Icon
        NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout);

        // Handle Navigation item clicks
        // This works with no further action on your part if the menu and destination id’s match.
        NavigationUI.setupWithNavController(navigationView, navController);

    }

    @Override
    public boolean onSupportNavigateUp() {
        // Allows NavigationUI to support proper up navigation or the drawer layout
        // drawer menu, depending on the situation.
        return NavigationUI.navigateUp(navController, drawerLayout);

    }
}

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

เพิ่มจุดหมายของกิจกรรม

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

ก่อนอื่น ให้ระบุตำแหน่งในแอปที่คุณมีกราฟการนำทาง 2 แบบแยกกัน และกำลังใช้ startActivity เพื่อเปลี่ยนรหัส

ตัวอย่างนี้มีกราฟ 2 แบบ (A และ B) และการเรียก startActivity() ไปยัง เปลี่ยนจาก A เป็น B

Kotlin

fun navigateToProductDetails(productId: String) {
    val intent = Intent(this, ProductDetailsActivity::class.java)
    intent.putExtra(KEY_PRODUCT_ID, productId)
    startActivity(intent)
}

Java

private void navigateToProductDetails(String productId) {
    Intent intent = new Intent(this, ProductDetailsActivity.class);
    intent.putExtra(KEY_PRODUCT_ID, productId);
    startActivity(intent);

จากนั้น แทนที่รายการเหล่านี้ด้วยปลายทางกิจกรรมในกราฟ A ที่แสดง การนำทางไปยังกิจกรรมโฮสต์ของกราฟ B หากคุณมีอาร์กิวเมนต์ที่จะส่งไปยัง ปลายทางเริ่มต้นของกราฟ B คุณกำหนดได้ในปลายทางกิจกรรม ของเรา

ในตัวอย่างต่อไปนี้ กราฟ A จะระบุปลายทางของกิจกรรมที่ต้องใช้ product_id พร้อมกับการดำเนินการ กราฟ B ไม่มีการเปลี่ยนแปลง

การแสดง XML ของกราฟ A และ B อาจมีลักษณะดังนี้

<!-- Graph A -->
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/product_list_graph"
    app:startDestination="@id/product_list">

    <fragment
        android:id="@+id/product_list"
        android:name="com.example.android.persistence.ui.ProductListFragment"
        android:label="Product List"
        tools:layout="@layout/product_list_fragment">
        <action
            android:id="@+id/navigate_to_product_detail"
            app:destination="@id/product_details_activity" />
    </fragment>

    <activity
        android:id="@+id/product_details_activity"
        android:name="com.example.android.persistence.ui.ProductDetailsActivity"
        android:label="Product Details"
        tools:layout="@layout/product_details_host">

        <argument
            android:name="product_id"
            app:argType="integer" />

    </activity>

</navigation>
<!-- Graph B -->
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    app:startDestination="@id/product_details">

    <fragment
        android:id="@+id/product_details"
        android:name="com.example.android.persistence.ui.ProductDetailsFragment"
        android:label="Product Details"
        tools:layout="@layout/product_details_fragment">
        <argument
            android:name="product_id"
            app:argType="integer" />
    </fragment>

</navigation>

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

Kotlin

fun navigateToProductDetails(productId: String) {
    val directions = ProductListDirections.navigateToProductDetail(productId)
    findNavController().navigate(directions)
}

Java

private void navigateToProductDetails(String productId) {
    ProductListDirections.NavigateToProductDetail directions =
            ProductListDirections.navigateToProductDetail(productId);
    Navigation.findNavController(getView()).navigate(directions);

ส่งผ่านอาร์กิวเมนต์ปลายทางของกิจกรรมไปยังส่วนย่อยของปลายทางเริ่มต้น

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

Kotlin

class ProductDetailsActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.product_details_host)
        val navHostFragment = supportFragmentManager.findFragmentById(R.id.main_content) as NavHostFragment
        val navController = navHostFramgent.navController
        navController
                .setGraph(R.navigation.product_detail_graph, intent.extras)
    }

}

Java

public class ProductDetailsActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.product_details_host);
        NavHostFragment navHostFragment = (NavHostFragment)
            getSupportFragmentManager().findFragmentById(R.id.main_content);
        NavController navController = navHostFragment.getNavController();
        navController
                .setGraph(R.navigation.product_detail_graph, getIntent().getExtras());
    }

}

คุณสามารถดึงข้อมูลออกจากอาร์กิวเมนต์แฟรกเมนต์ Bundle โดยใช้ คลาสอาร์กิวเมนต์ที่สร้างขึ้นดังที่ปรากฏในตัวอย่างต่อไปนี้

Kotlin

class ProductDetailsFragment : Fragment() {

    val args by navArgs<ProductDetailsArgs>()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        val productId = args.productId
        ...
    }
    ...

Java

public class ProductDetailsFragment extends Fragment {

    ProductDetailsArgs args;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        args = ProductDetailsArgs.fromBundle(requireArguments());
    }

    @Override
    public void onViewCreated(@NonNull View view,
            @Nullable Bundle savedInstanceState) {
       int productId = args.getProductId();
       ...
    }
    ...

รวมกิจกรรม

คุณสามารถรวมกราฟการนำทางในกรณีที่กิจกรรมหลายอย่างใช้ เลย์เอาต์เดียวกัน เช่น FrameLayout แบบง่ายที่มีส่วนย่อยเดียว ใน ส่วนใหญ่แล้ว คุณสามารถรวม องค์ประกอบทั้งหมดจาก กราฟการนำทางและอัปเดตองค์ประกอบปลายทางของกิจกรรมให้เป็นส่วนย่อย ปลายทาง

ตัวอย่างต่อไปนี้รวมกราฟ A และ B จากส่วนก่อนหน้าเข้าด้วยกัน

ก่อนผสานรวม

<!-- Graph A -->
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/product_list_graph"
    app:startDestination="@id/product_list">

    <fragment
        android:id="@+id/product_list"
        android:name="com.example.android.persistence.ui.ProductListFragment"
        android:label="Product List Fragment"
        tools:layout="@layout/product_list">
        <action
            android:id="@+id/navigate_to_product_detail"
            app:destination="@id/product_details_activity" />
    </fragment>
    <activity
        android:id="@+id/product_details_activity"
        android:name="com.example.android.persistence.ui.ProductDetailsActivity"
        android:label="Product Details Host"
        tools:layout="@layout/product_details_host">
        <argument android:name="product_id"
            app:argType="integer" />
    </activity>

</navigation>
<!-- Graph B -->
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/product_detail_graph"
    app:startDestination="@id/product_details">

    <fragment
        android:id="@+id/product_details"
        android:name="com.example.android.persistence.ui.ProductDetailsFragment"
        android:label="Product Details"
        tools:layout="@layout/product_details">
        <argument
            android:name="product_id"
            app:argType="integer" />
    </fragment>
</navigation>

หลังจากผสานรวมแล้ว:

<!-- Combined Graph A and B -->
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/product_list_graph"
    app:startDestination="@id/product_list">

    <fragment
        android:id="@+id/product_list"
        android:name="com.example.android.persistence.ui.ProductListFragment"
        android:label="Product List Fragment"
        tools:layout="@layout/product_list">
        <action
            android:id="@+id/navigate_to_product_detail"
            app:destination="@id/product_details" />
    </fragment>

    <fragment
        android:id="@+id/product_details"
        android:name="com.example.android.persistence.ui.ProductDetailsFragment"
        android:label="Product Details"
        tools:layout="@layout/product_details">
        <argument
            android:name="product_id"
            app:argType="integer" />
    </fragment>

</navigation>

การตั้งชื่อการกระทำให้เหมือนเดิมขณะรวมก็ช่วยให้การดำเนินการนี้เป็นไปอย่างราบรื่น โดยไม่ต้องเปลี่ยนแปลงฐานของโค้ดที่มีอยู่ ตัวอย่างเช่น navigateToProductDetail ยังคงเหมือนเดิมที่นี่ ความแตกต่างเพียงอย่างเดียวคือ การดำเนินการนี้จะแสดงการนำทางไปยังปลายทางของส่วนย่อยภายใน NavHost แทนที่จะเป็นปลายทางของกิจกรรม:

Kotlin

fun navigateToProductDetails(productId: String) {
    val directions = ProductListDirections.navigateToProductDetail(productId)
    findNavController().navigate(directions)
}

Java

private void navigateToProductDetails(String productId) {
    ProductListDirections.NavigateToProductDetail directions =
            ProductListDirections.navigateToProductDetail(productId);
    Navigation.findNavController(getView()).navigate(directions);

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

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