Chuyển sang dùng thành phần Điều hướng

Thành phần điều hướng (Navigation component) là một thư viện có thể quản lý chức năng điều hướng phức tạp, ảnh động chuyển đổi, liên kết sâu cũng như việc truyền đối số đã kiểm tra khi biên dịch qua các màn hình trong ứng dụng.

Tài liệu này đóng vai trò là hướng dẫn chung cho việc chuyển sang sử dụng Thành phần điều hướng cho một ứng dụng hiện có.

Nhìn chung, quá trình di chuyển bao gồm các bước sau:

  1. Di chuyển logic giao diện người dùng theo màn hình cụ thể ra khỏi hoạt động – Di chuyển logic giao diện người dùng của ứng dụng ra khỏi hoạt động (activity), đảm bảo rằng mỗi hoạt động chỉ sở hữu logic của các thành phần giao diện người dùng điều hướng chung, chẳng hạn như Toolbar, trong khi uỷ quyền hoạt động triển khai từng màn hình cho một mảnh hoặc đích đến tuỳ chỉnh.

  2. Tích hợp Thành phần điều hướng – Đối với mỗi hoạt động, hãy xây dựng một biểu đồ điều hướng chứa ít nhất một mảnh mà hoạt động đó quản lý. Thay thế giao tác mảnh bằng thao tác Thành phần điều hướng.

  3. Thêm đích đến cho hoạt động (activity destination) – Thay thế lệnh gọi startActivity() bằng thao tác sử dụng đích đến cho hoạt động.

  4. Kết hợp các hoạt động – Kết hợp các biểu đồ điều hướng trong trường hợp nhiều hoạt động có chung một bố cục.

Điều kiện tiên quyết

Hướng dẫn này giả định rằng bạn đã chuyển sang sử dụng các thư viện AndroidX cho ứng dụng. Nếu bạn chưa làm như vậy, hãy chuyển dự án sang sử dụng AndroidX trước khi tiếp tục.

Di chuyển logic giao diện người dùng theo màn hình cụ thể ra khỏi hoạt động

Hoạt động (activity) là các thành phần cấp hệ thống hỗ trợ tương tác đồ hoạ giữa ứng dụng và Android. Hoạt động được đăng ký trong tệp kê khai của ứng dụng để Android biết được nên khởi chạy những hoạt động nào. Lớp hoạt động (activity class) cho phép ứng dụng phản ứng với các thay đổi trong Android, chẳng hạn như khi giao diện người dùng của ứng dụng vào hoặc ra khỏi chế độ nền trước, xoay, v.v. Hoạt động cũng có thể là một nơi để chia sẻ trạng thái (state) giữa các màn hình.

Đối với ứng dụng của bạn, các hoạt động nên đóng vai trò là máy chủ lưu trữ để điều hướng, đồng thời nên có logic và kiến thức về cách chuyển đổi giữa các màn hình, truyền dữ liệu, v.v. Tuy nhiên, việc quản lý thông tin chi tiết về giao diện người dùng sẽ phù hợp hơn với một phần nhỏ hơn và dễ sử dụng lại trên giao diện người dùng. Cách triển khai đề xuất cho mẫu này là mảnh (fragment). Hãy xem bài viết Hoạt động đơn: Lý do, thời điểm và cách thức để tìm hiểu thêm về các ưu điểm khi sử dụng mảnh. Thành phần điều hướng hỗ trợ mảnh qua phần phụ thuộc navigation-fragment. Thành phần điều hướng cũng hỗ trợ các loại đích tuỳ chỉnh.

Nếu ứng dụng của bạn không sử dụng mảnh, điều đầu tiên bạn cần làm là di chuyển từng màn hình trong ứng dụng để dùng mảnh. Bạn không xoá hoạt động tại thời điểm này. Thay vào đó, bạn sẽ tạo mảnh để đại diện cho màn hình và chia nhỏ logic giao diện người dùng theo trách nhiệm.

Đưa mảnh vào ứng dụng

Để minh hoạ quá trình đưa mảnh vào ứng dụng, hãy bắt đầu bằng ví dụ về một ứng dụng bao gồm hai màn hình: màn hình danh sách sản phẩmthông tin chi tiết về sản phẩm. Khi nhấp vào một sản phẩm trong màn hình danh sách, người dùng sẽ được chuyển đến màn hình thông tin chi tiết để tìm hiểu thêm về sản phẩm đó.

Trong ví dụ này, các màn hình danh sách và thông tin chi tiết hiện là các hoạt động riêng biệt.

Tạo bố cục mới để lưu trữ giao diện người dùng

Để đưa mảnh vào ứng dụng, hãy bắt đầu bằng cách tạo một tệp bố cục mới cho hoạt động để lưu trữ mảnh đó. Thao tác này sẽ thay thế bố cục thành phần hiển thị nội dung hiện tại của hoạt động.

Để có một khung hiển thị đơn giản, bạn có thể sử dụng FrameLayout, như trong ví dụ product_list_host sau:

<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" />

Thuộc tính id đề cập đến phần nội dung mà sau đó chúng ta sẽ thêm mảnh.

Tiếp theo, trong hàm onCreate() của hoạt động, hãy sửa đổi mã tham chiếu tệp bố cục trong hàm onCreate của hoạt động để trỏ đến tệp bố cục mới này:

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);
        ...
    }
}

Bố cục hiện tại (product_list trong ví dụ này) được dùng làm khung hiển thị gốc cho mảnh bạn sắp tạo.

Tạo mảnh

Hãy tạo mảnh mới để quản lý giao diện người dùng cho màn hình. Bạn nên đảm bảo nhất quán với tên máy chủ lưu trữ hoạt động. Đoạn mã sau đây sử dụng ProductListFragment, ví dụ:

Kotlin

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

Java

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

Di chuyển logic hoạt động sang mảnh

Khi đã có phần định nghĩa mảnh, bước tiếp theo là di chuyển logic giao diện người dùng cho màn hình từ hoạt động này sang mảnh mới này. Nếu xuất phát từ một cấu trúc dựa trên hoạt động, có thể bạn sẽ có nhiều logic tạo khung hiển thị diễn ra trong hàm onCreate() của hoạt động.

Sau đây là ví dụ về một màn hình dựa trên hoạt động có chứa logic giao diện người dùng mà chúng ta cần di chuyển:

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
   }

Cũng có thể hoạt động của bạn kiểm soát thời điểm và cách người dùng chuyển đến màn hình tiếp theo, như trong ví dụ sau:

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);
}

Bên trong mảnh, bạn phân phối công việc này giữa onCreateView()onViewCreated(), chỉ với logic điều hướng vẫn còn trong hoạt động:

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);
            }
        }
    };
    ...
}

Trong ProductListFragment, hãy lưu ý rằng không có lệnh gọi tới setContentView() để tăng cường và kết nối bố cục này. Trong mảnh, onCreateView() sẽ khởi chạy thành phần hiển thị gốc. onCreateView() lấy một thực thể của LayoutInflater có thể dùng để tăng cường khung hiển thị gốc dựa trên tệp tài nguyên bố cục. Ví dụ này sử dụng lại bố cục product_list hiện có của hoạt động vì không cần thay đổi bố cục cho chính bố cục đó.

Nếu có logic giao diện người dùng bất kỳ nằm trong các chức năng onStart(), onResume(), onPause() hoặc onStop() của hoạt động không liên quan đến thành phần điều hướng, thì bạn có thể chuyển các chức năng đó sang các chức năng tương ứng cùng tên trên mảnh.

Khởi động mảnh trong hoạt động của máy chủ lưu trữ

Khi bạn đã di chuyển tất cả logic giao diện người dùng xuống mảnh, trong hoạt động sẽ chỉ còn lại logic điều hướng.

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);
    }
}

Bước cuối cùng là tạo thực thể của mảnh trong onCreate(), ngay sau khi đặt khung hiển thị nội dung:

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();
    }
}

Như trong ví dụ này, FragmentManager tự động lưu và khôi phục các mảnh dựa trên các thay đổi về cấu hình, vì vậy, bạn chỉ cần thêm mảnh nếu giá trị của savedInstanceState là rỗng (null).

Truyền mã bổ sung ý định vào mảnh

Nếu hoạt động của bạn nhận được Extras qua một ý định (intent), thì bạn có thể trực tiếp truyền mã này sang mảnh dưới dạng đối số.

Trong ví dụ này, ProductDetailsFragment trực tiếp nhận được đối số qua các mã bổ sung ý định (intent extra) của hoạt động:

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();
}

...

Đến đây, bạn có thể kiểm thử quá trình chạy ứng dụng, trong đó màn hình đầu tiên được cập nhật để sử dụng mảnh. Tiếp tục di chuyển các màn hình dựa trên hoạt động còn lại, dành thời gian kiểm thử sau mỗi lần lặp lại.

Tích hợp Thành phần điều hướng

Khi sử dụng cấu trúc dựa trên mảnh, bạn có thể bắt đầu tích hợp Thành phần điều hướng.

Trước tiên, hãy thêm các phần phụ thuộc điều hướng gần đây nhất vào dự án, theo hướng dẫn trong Ghi chú phát hành thư viện điều hướng.

Tạo biểu đồ điều hướng

Thành phần điều hướng thể hiện cấu hình điều hướng của ứng dụng trong tệp tài nguyên dưới dạng biểu đồ, giống như khung hiển thị của ứng dụng. Việc này giúp sắp xếp hợp lý hoạt động điều hướng của ứng dụng bên ngoài bộ mã cơ sở, đồng thời giúp bạn chỉnh sửa hoạt động điều hướng trong ứng dụng một cách trực quan.

Để tạo biểu đồ điều hướng, hãy bắt đầu bằng cách tạo một thư mục tài nguyên mới có tên navigation. Để thêm biểu đồ, hãy nhấp chuột phải vào thư mục này rồi chọn New > Navigation resource file (Mới > Tệp tài nguyên điều hướng).

Thành phần điều hướng sử dụng một hoạt động làm máy chủ lưu trữ để điều hướng và hoán đổi từng mảnh riêng lẻ vào máy chủ đó khi người dùng di chuyển trong ứng dụng. Trước khi có thể bắt đầu tạo bố cục bằng hình ảnh cho thành phần điều hướng của ứng dụng, bạn cần định cấu hình NavHost bên trong hoạt động sẽ lưu trữ biểu đồ này. Vì đang sử dụng mảnh, nên chúng ta có thể dùng cách triển khai NavHost mặc định của Thành phần điều hướng là NavHostFragment.

NavHostFragment được định cấu hình qua FragmentContainerView nằm trong một hoạt động lưu trữ, như trong ví dụ sau:

<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" />

Thuộc tính app:NavGraph trỏ đến biểu đồ điều hướng được liên kết với máy chủ điều hướng này. Thao tác đặt thuộc tính này sẽ tăng cường biểu đồ điều hướng và đặt thuộc tính biểu đồ trên NavHostFragment. Thuộc tính app:defaultNavHost đảm bảo rằng NavHostFragment sẽ chặn nút Quay lại của hệ thống.

Nếu bạn đang sử dụng thành phần điều hướng cấp cao, chẳng hạn như DrawerLayout hoặc BottomNavigationView, thì FragmentContainerView sẽ thay thế phần tử khung hiển thị nội dung chính của bạn. Hãy xem ví dụ trong nội dung Sử dụng NavigationUI để cập nhật thành phần giao diện người dùng.

Đối với một bố cục đơn giản, bạn có thể đưa phần tử FragmentContainerView này vào làm phần tử con của thư mục gốc 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>

Nếu nhấp vào thẻ Design (Thiết kế) ở dưới cùng, thì bạn sẽ thấy một biểu đồ tương tự như biểu đồ dưới đây. Ở phía trên bên trái của biểu đồ, trong phần Destinations (Đích đến), bạn có thể thấy một mã tham chiếu đến hoạt động NavHost ở dạng layout_name (resource_id).

Nhấp vào nút dấu cộng gần phía trên cùng để thêm các mảnh của bạn vào biểu đồ này.

Thành phần điều hướng chính là các màn hình riêng lẻ dùng làm đích đến (destination). Đích đến có thể là mảnh, hoạt động hoặc đích đến tuỳ chỉnh. Bạn có thể thêm mọi loại đích đến vào biểu đồ, nhưng hãy lưu ý rằng đích đến cho hoạt động được coi là đích đến cuối, vì sau khi điều hướng đến đích đến của hoạt động, bạn sẽ hoạt động bên trong một máy chủ lưu trữ và biểu đồ riêng.

Thành phần điều hướng cũng chính là cách người dùng di chuyển từ đích đến này tới đích đến khác dưới dạng hành động (action). Hành động cũng có thể mô tả ảnh động chuyển đổi và hành vi bật ra.

Xoá giao tác mảnh

Giờ đây bạn đang sử dụng Thành phần điều hướng. Nếu đang di chuyển giữa các màn hình dựa trên mảnh trong cùng một hoạt động, thì bạn có thể xoá các lượt tương tác FragmentManager.

Nếu ứng dụng của bạn đang sử dụng nhiều mảnh trong cùng một hoạt động hoặc thành phần điều hướng cấp cao (chẳng hạn như bố cục ngăn hoặc ngăn điều hướng ở dưới cùng), thì có thể bạn đang sử dụng FragmentManagerFragmentTransactions để thêm hoặc thay thế mảnh trong phần nội dung chính của giao diện người dùng. Việc này hiện có thể được thay thế và đơn giản hoá qua Thành phần điều hướng bằng cách cung cấp các hành động để liên kết các đích đến trong biểu đồ rồi điều hướng bằng NavController.

Sau đây là một vài tình huống mà bạn có thể gặp phải cũng như cách di chuyển trong từng tình huống.

Một hoạt động quản lý nhiều mảnh

Nếu bạn có một hoạt động quản lý nhiều mảnh, thì mã hoạt động của bạn có thể có dạng như sau:

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();
    }
}

Bên trong đích của nguồn, bạn có thể gọi hàm điều hướng để phản hồi một sự kiện nào đó, như trình bày dưới đây:

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())
    );
}

Bạn có thể thay thế bằng cách cập nhật biểu đồ điều hướng để đặt hành động và đích đến bắt đầu nhằm liên kết các đích đến cũng như xác định các đối số khi cần:

<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>

Sau đó, bạn có thể cập nhật hoạt động:

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);
    }
}

Hoạt động không còn phải dùng phương thức navigateToProductDetail() nữa. Trong phần tiếp theo, chúng ta cập nhật ProductListFragment để sử dụng NavController nhằm di chuyển đến màn hình thông tin chi tiết sản phẩm tiếp theo.

Truyền đối số một cách an toàn

Thành phần điều hướng có một trình bổ trợ Gradle tên là Safe Args. Trình bổ trợ này tạo ra các lớp xây dựng và đối tượng đơn giản để truy cập kiểu an toàn (type-safe) vào các đối số được chỉ định cho đích đến và hành động.

Sau khi áp dụng trình bổ trợ, mọi đối số được xác định tại một đích đến trong biểu đồ điều hướng sẽ đều khiến khung Thành phần điều hướng tạo ra một lớp Arguments cung cấp đối số kiểu an toàn cho đích đến mục tiêu. Việc xác định một hành động sẽ khiến trình bổ trợ tạo ra một lớp cấu hình Directions có thể dùng để thông báo cho NavController biết cách điều hướng người dùng đến đích đến mục tiêu. Khi một hành động trỏ đến một đích đến cần đến các đối số, lớp Directions đã tạo sẽ có cả các phương thức hàm khởi tạo cần đến các tham số đó.

Bên trong mảnh, hãy sử dụng NavController và lớp Directions đã tạo để cung cấp các đối số kiểu an toàn cho đích đến, như trong ví dụ sau:

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);
    };
}

Thành phần điều hướng cấp cao

Nếu ứng dụng của bạn sử dụng DrawerLayout, thì có thể bạn sẽ thấy nhiều logic cấu hình trong hoạt động quản lý thao tác mở và đóng ngăn cũng như điều hướng đến các đích đến khác.

Hoạt động bạn tạo ra có thể có dạng như sau:

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);
    }
}

Sau khi bạn đã thêm Thành phần điều hướng vào dự án và tạo biểu đồ điều hướng, hãy thêm từng đích nội dung trên biểu đồ của bạn (chẳng hạn như Home (Trang chủ), Gallery (Thư viện ảnh), SlideShow (Trình chiếu) và Tools (Công cụ) trong ví dụ trên). Hãy đảm bảo rằng giá trị id của mục trong trình đơn khớp với giá trị id của đích đến được liên kết, như trình bày dưới đây:

<!-- 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>

Khi khớp các giá trị id trên trình đơn và biểu đồ, bạn cũng có thể kết nối NavController cho hoạt động này để xử lý chế độ tự động điều hướng dựa trên mục trong trình đơn. NavController cũng xử lý thao tác mở và đóng DrawerLayout cũng như xử lý hành vi của nút Lên (Up) và Quay lại (Back) một cách thích hợp.

Sau đó, bạn có thể cập nhật MainActivity để kết nối NavController với ToolbarNavigationView.

Hãy xem đoạn mã minh hoạ sau:

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);

    }
}

Bạn có thể sử dụng chính kỹ thuật này cho cả thành phần điều hướng dựa trên BottomNavigationView và thành phần điều hướng dựa trên trình đơn (menu). Hãy xem ví dụ trong nội dung Sử dụng NavigationUI để cập nhật thành phần giao diện người dùng.

Thêm đích đến cho hoạt động

Sau khi mỗi màn hình trong ứng dụng đã được kết nối để sử dụng Thành phần điều hướng và bạn không cần sử dụng FragmentTransactions để chuyển đổi giữa các đích đến dựa trên mảnh nữa, bước tiếp theo là loại bỏ các lệnh gọi startActivity.

Trước tiên, hãy xác định các vị trí trong ứng dụng nơi có hai biểu đồ điều hướng riêng biệt và bạn đang sử dụng startActivity để chuyển đổi giữa các vị trí đó.

Ví dụ này cho thấy hai biểu đồ (A và B) và một lệnh gọi startActivity() để chuyển đổi từ A sang 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);

Tiếp theo, hãy thay thế các vị trí này bằng một đích đến cho hoạt động trong Biểu đồ A. Biểu đồ này đại diện cho quá trình điều hướng đến hoạt động lưu trữ của Biểu đồ B. Nếu có các đối số để truyền đến đích đến bắt đầu của Biểu đồ B, thì bạn có thể chỉ định chúng trong phần định nghĩa đích đến cho hoạt động.

Trong ví dụ sau, Biểu đồ A xác định đích đến cho hoạt động có đối số product_id cùng với một hành động. Biểu đồ B không chứa thay đổi nào.

XML của Biểu đồ A và Biểu đồ B có thể được thể hiện như sau:

<!-- 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ạn có thể chuyển đến hoạt động lưu trữ của Biểu đồ B bằng chính cơ chế mà bạn sử dụng để di chuyển đến các đích đến của mảnh:

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);

Truyền đối số đích đến cho hoạt động sang mảnh đích đến bắt đầu

Nếu hoạt động đích đến nhận được mã bổ sung (extra) như trong ví dụ trước, thì bạn có thể trực tiếp truyền những dữ liệu này đến đích đến bắt đầu dưới dạng đối số. Tuy nhiên, bạn phải đặt biểu đồ điều hướng của máy chủ theo cách thủ công bên trong onCreate() để có thể truyền mã bổ sung ý định (intent extra) dưới dạng đối số sang mảnh, như trình bày dưới đây:

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());
    }

}

Bạn có thể lấy dữ liệu ra khỏi đối số mảnh Bundle bằng cách sử dụng lớp đối số đã tạo, như trong ví dụ sau:

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();
       ...
    }
    ...

Kết hợp các hoạt động

Bạn có thể kết hợp các biểu đồ điều hướng trong trường hợp nhiều hoạt động có cùng một bố cục, chẳng hạn như một FrameLayout đơn giản chứa một mảnh đơn lẻ. Trong hầu hết trường hợp như vậy, bạn chỉ cần kết hợp tất cả phần tử trên mỗi biểu đồ điều hướng rồi cập nhật mọi phần tử đích đến cho hoạt động thành các đích đến cho mảnh.

Ví dụ sau đây kết hợp các Biểu đồ A và B ở phần trước:

Trước khi kết hợp:

<!-- 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>

Sau khi kết hợp:

<!-- 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>

Việc giữ nguyên tên hành động trong khi hợp nhất có thể giúp quá trình này diễn ra liền mạch mà không đòi hỏi bạn phải chỉnh sửa mã cơ sở hiện tại. Ví dụ: navigateToProductDetail vẫn được giữ nguyên ở đây. Điểm khác biệt duy nhất là thao tác này giờ đây đại diện cho quá trình điều hướng đến một đích đến cho mảnh trong cùng NavHost thay vì một đích đến cho hoạt động:

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);

Tài nguyên khác

Để biết thêm thông tin liên quan đến thành phần điều hướng, hãy xem các chủ đề sau: