Thư viện Dynamic Navigator sẽ mở rộng chức năng của thành phần Điều hướng Jetpack để liên kết với các đích đến được xác định trong mô-đun tính năng. Thư viện này cũng cung cấp dịch vụ cài đặt liền mạch các mô-đun tính năng theo yêu cầu khi điều hướng đến những đích đến này.
Thiết lập
Để hỗ trợ các mô-đun tính năng, hãy sử dụng các phần phụ thuộc sau trong tệp build.gradle
của mô-đun ứng dụng:
Groovy
dependencies { def nav_version = "2.7.7" api "androidx.navigation:navigation-fragment-ktx:$nav_version" api "androidx.navigation:navigation-ui-ktx:$nav_version" api "androidx.navigation:navigation-dynamic-features-fragment:$nav_version" }
Kotlin
dependencies { val nav_version = "2.7.7" api("androidx.navigation:navigation-fragment-ktx:$nav_version") api("androidx.navigation:navigation-ui-ktx:$nav_version") api("androidx.navigation:navigation-dynamic-features-fragment:$nav_version") }
Lưu ý các phần phụ thuộc Điều hướng khác phải dùng cấu hình api để luôn sử dụng được cho các mô-đun tính năng.
Cách dùng cơ bản
Để hỗ trợ các mô-đun tính năng, trước tiên hãy thay đổi mọi NavHostFragment
trong ứng dụng thành androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment
:
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment"
app:navGraph="@navigation/nav_graph"
... />
Tiếp theo, hãy thêm thuộc tính app:moduleName
vào bất kỳ đích đến <activity>
, <fragment>
hoặc <navigation>
nào trong biểu đồ điều hướng của mô-đun com.android.dynamic-feature
được liên kết vớiDynamicNavHostFragment
.
Thuộc tính này báo cho Thư viện Dynamic Navigator biết đích đến thuộc một mô-đun tính năng với tên đã được chỉ định.
<fragment
app:moduleName="myDynamicFeature"
android:id="@+id/featureFragment"
android:name="com.google.android.samples.feature.FeatureFragment"
... />
Khi bạn điều hướng đến một trong các đích đến này, trước tiên Thư viện Dynamic Navigator sẽ kiểm tra xem mô-đun tính năng có được cài đặt chưa. Nếu đã có mô-đun tính năng, ứng dụng sẽ điều hướng đến đích đến như dự kiến. Nếu không có mô-đun, ứng dụng sẽ hiển thị đích đến là một mảnh tiến trình trung gian khi cài đặt mô-đun. Theo mặc định, khi triển khai mảnh tiến trình, màn hình sẽ hiển thị giao diện người dùng cơ bản với thanh tiến trình và xử lý mọi lỗi cài đặt.
![hai màn hình tải dữ liệu cho thấy giao diện người dùng với thanh tiến trình khi điều hướng đến một mô-đun tính năng lần đầu](https://developer.android.com/static/images/guide/navigation/dfm-nav-loading.png?authuser=9&hl=vi)
Để tùy chỉnh giao diện người dùng hoặc xử lý theo cách thủ công quá trình cài đặt từ trong màn hình ứng dụng, hãy xem phần Tùy chỉnh mảnh tiến trình và Theo dõi trạng thái yêu cầu trong chủ đề này.
Các đích đến không chỉ định app:moduleName
vẫn tiếp tục hoạt động mà không có các thay đổi đồng thời chúng vận hành như thể ứng dụng sử dụng NavHostFragment
thông thường.
Tùy chỉnh mảnh tiến trình
Có thể ghi đè phương thức triển khai mảnh tiến trình cho từng biểu đồ điều hướng bằng cách đặt thuộc tính app:progressDestination
thành ID của đích đến mà bạn muốn sử dụng để xử lý tiến trình cài đặt. Đích đến tiến trình tuỳ chỉnh của bạn phải là Fragment
bắt nguồn từ AbstractProgressFragment
.
Bạn phải ghi đè các phương thức trừu tượng (abstract) cho thông báo về tiến trình cài đặt, lỗi và các sự kiện khác. Sau đó, bạn có thể hiển thị tiến trình cài đặt trong giao diện người dùng đã chọn.
Lớp DefaultProgressFragment
của quy trình triển khai mặc định sẽ sử dụng API này để hiển thị tiến trình cài đặt.
Theo dõi trạng thái của yêu cầu
Thư viện Dynamic Navigator cho phép triển khai một luồng UX (trải nghiệm người dùng) tương tự như trong Các phương pháp thiết kế trải nghiệm người dùng hay nhất để phân phối theo yêu cầu, trong đó người dùng đợi ở màn hình trước trong khi chờ quá trình cài đặt hoàn tất. Nghĩa là bạn không cần hiển thị giao diện người dùng trung gian hay mảnh tiến trình.
![màn hình hiển thị thanh điều hướng ở dưới cùng với một biểu tượng cho biết mô-đun tính năng đang được tải xuống](https://developer.android.com/static/images/guide/navigation/nav-dfm-ui.png?authuser=9&hl=vi)
Trong trường hợp này, bạn chịu trách nhiệm theo dõi và xử lý tất cả các trạng thái cài đặt cũng như thay đổi về tiến trình, lỗi, v.v.
Để bắt đầu luồng điều hướng không bị chặn này, hãy truyền đối tượng DynamicExtras
chứa DynamicInstallMonitor
đến NavController.navigate()
, như trong ví dụ sau:
Kotlin
val navController = ... val installMonitor = DynamicInstallMonitor() navController.navigate( destinationId, null, null, DynamicExtras(installMonitor) )
Java
NavController navController = ... DynamicInstallMonitor installMonitor = new DynamicInstallMonitor(); navController.navigate( destinationId, null, null, new DynamicExtras(installMonitor); )
Ngay sau khi gọi navigate()
, bạn phải kiểm tra giá trị của installMonitor.isInstallRequired
để xem liệu thao tác điều hướng đã thử có cài đặt mô-đun tính năng hay không.
- Nếu giá trị là
false
, tức là bạn đang điều hướng đến một đích đến bình thường và không cần làm gì thêm. Nếu giá trị là
true
, bạn nên bắt đầu quan sát đối tượngLiveData
hiện có tronginstallMonitor.status
. Đối tượngLiveData
này tạo ra nội dung cập nhậtSplitInstallSessionState
từ thư viện Play Core. Những nội dung cập nhật này chứa các sự kiện tiến trình cài đặt mà bạn có thể sử dụng để cập nhật giao diện người dùng. Hãy nhớ xử lý mọi trạng thái liên quan như đã nêu trong hướng dẫn Play Core, bao gồm yêu cầu người dùng xác nhận nếu cần thiết.Kotlin
val navController = ... val installMonitor = DynamicInstallMonitor() navController.navigate( destinationId, null, null, DynamicExtras(installMonitor) ) if (installMonitor.isInstallRequired) { installMonitor.status.observe(this, object : Observer<SplitInstallSessionState> { override fun onChanged(sessionState: SplitInstallSessionState) { when (sessionState.status()) { SplitInstallSessionStatus.INSTALLED -> { // Call navigate again here or after user taps again in the UI: // navController.navigate(destinationId, destinationArgs, null, null) } SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION -> { SplitInstallManager.startConfirmationDialogForResult(...) } // Handle all remaining states: SplitInstallSessionStatus.FAILED -> {} SplitInstallSessionStatus.CANCELED -> {} } if (sessionState.hasTerminalStatus()) { installMonitor.status.removeObserver(this); } } }); }
Java
NavController navController = ... DynamicInstallMonitor installMonitor = new DynamicInstallMonitor(); navController.navigate( destinationId, null, null, new DynamicExtras(installMonitor); ) if (installMonitor.isInstallRequired()) { installMonitor.getStatus().observe(this, new Observer<SplitInstallSessionState>() { @Override public void onChanged(SplitInstallSessionState sessionState) { switch (sessionState.status()) { case SplitInstallSessionStatus.INSTALLED: // Call navigate again here or after user taps again in the UI: // navController.navigate(mDestinationId, mDestinationArgs, null, null); break; case SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION: SplitInstallManager.startConfirmationDialogForResult(...) break; // Handle all remaining states: case SplitInstallSessionStatus.FAILED: break; case SplitInstallSessionStatus.CANCELED: break; } if (sessionState.hasTerminalStatus()) { installMonitor.getStatus().removeObserver(this); } } }); }
Khi quá trình cài đặt kết thúc, đối tượng LiveData
sẽ tạo ra trạng thái SplitInstallSessionStatus.INSTALLED
. Sau đó, bạn phải gọi lại hàm NavController.navigate()
. Vì giờ đây mô-đun đã được cài đặt nên lệnh gọi sẽ thành công và ứng dụng sẽ điều hướng đến đích như mong đợi.
Sau khi đạt đến trạng thái kết thúc, ví dụ như khi cài đặt xong hoặc khi cài đặt không thành công, bạn nên xóa bộ quan sát LiveData
để tránh bị rò rỉ bộ nhớ. Có thể kiểm tra xem trạng thái hiện tại có phải là trạng thái kết thúc hay không bằng cách dùng SplitInstallSessionStatus.hasTerminalStatus()
.
Hãy xem AbstractProgressFragment
để biết ví dụ về cách triển khai trình quan sát này.
Biểu đồ đi kèm
Thư viện Dynamic Navigator hỗ trợ cả biểu đồ được xác định trong các mô-đun tính năng. Để sử dụng một biểu đồ được xác định trong mô-đun tính năng, hãy làm như sau:
Sử dụng
<include-dynamic/>
thay vì<include/>
, như trong ví dụ sau:<include-dynamic android:id="@+id/includedGraph" app:moduleName="includedgraphfeature" app:graphResName="included_feature_nav" app:graphPackage="com.google.android.samples.dynamic_navigator.included_graph_feature" />
Bạn phải chỉ định các thuộc tính sau bên trong
<include-dynamic ... />
:app:graphResName
: tên của tệp tài nguyên biểu đồ điều hướng. Tên lấy từ tên tệp của biểu đồ. Ví dụ: nếu biểu đồ nằm trongres/navigation/nav_graph.xml
, thì tên tài nguyên sẽ lànav_graph
.android:id
– ID đích đến của biểu đồ. Thư viện Dynamic Navigator bỏ qua mọi giá trịandroid:id
được tìm thấy trong phần tử gốc của biểu đồ đi kèm.app:moduleName
: tên gói của mô-đun.
Sử dụng đúng graphPackage
Bạn phải lấy đúng app:graphPackage
, nếu không thành phần Điều hướng sẽ không thể bao gồm navGraph
được chỉ định từ mô-đun tính năng.
Tên gói của một mô-đun tính năng linh hoạt được tạo bằng cách thêm tên của mô-đun vào applicationId
của mô-đun ứng dụng cơ sở. Vì vậy, nếu mô-đun ứng dụng cơ sở có applicationId
trêncom.example.dynamicfeatureapp
và mô-đun tính năng linh hoạt được đặt tên là DynamicFeatureModule
, tên gói của mô-đun linh hoạt sẽ làcom.example.dynamicfeatureapp.DynamicFeatureModule
. Tên gói này có phân biệt chữ hoa và chữ thường.
Nếu không chắc chắn, bạn có thể xác nhận tên gói của mô-đun tính năng bằng cách kiểm tra AndroidManifest.xml
được tạo. Sau khi tạo dự án, hãy truy cập <DynamicFeatureModule>/build/intermediates/merged_manifest/debug/AndroidManifest.xml
, mã này có dạng như sau:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:dist="http://schemas.android.com/apk/distribution" featureSplit="DynamicFeatureModule" package="com.example.dynamicfeatureapp" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" /> <dist:module dist:instant="false" dist:title="@string/title_dynamicfeaturemodule" > <dist:delivery> <dist:install-time /> </dist:delivery> <dist:fusing dist:include="true" /> </dist:module> <application /> </manifest>
Giá trị featureSplit
phải khớp với tên của mô-đun tính năng linh hoạt, còn gói sẽ khớp với applicationId
của mô-đun ứng dụng cơ sở. app:graphPackage
là sự kết hợp của các giá trị này: com.example.dynamicfeatureapp.DynamicFeatureModule
.
Chuyển đến biểu đồ điều hướng linh hoạt
Bạn chỉ có thể chuyển đến startDestination
của biểu đồ điều hướng include-dynamic
. Mô-đun linh hoạt chịu trách nhiệm về biểu đồ điều hướng của riêng nó và ứng dụng cơ sở không biết được thông tin này.
Cơ chế linh hoạt cho phép mô-đun ứng dụng cơ sở liên kết biểu đồ điều hướng lồng nhau được xác định trong mô-đun linh hoạt. Biểu đồ điều hướng lồng nhau này cũng hoạt động giống các biểu đồ điều hướng lồng nhau khác. Biểu đồ điều hướng gốc (tức là biểu đồ gốc của biểu đồ điều hướng lồng nhau) chỉ có thể xác định chính biểu đồ điều hướng lồng nhau dưới dạng một đích đến chứ không phải là đích đến con của biểu đồ đó. Do đó, startDestination
được sử dụng khi biểu đồ điều hướng linh hoạt là đích đến.
Hạn chế
- Biểu đồ động hiện không hỗ trợ liên kết sâu.
- Biểu đồ lồng nhau chủ động tải linh hoạt (nghĩa là phần tử
<navigation>
cóapp:moduleName
) hiện không hỗ trợ liên kết sâu.