Trang này hướng dẫn cách mô-đun hoá mã điều hướng. Tài liệu này nhằm bổ sung cho hướng dẫn chung về mô-đun hoá ứng dụng.
Tổng quan
Mô-đun hoá mã điều hướng là quá trình tách các khoá điều hướng có liên quan và nội dung mà các khoá đó đại diện thành các mô-đun riêng lẻ. Điều này giúp phân tách rõ ràng các trách nhiệm và cho phép bạn di chuyển giữa các tính năng khác nhau trong ứng dụng.
Để mô-đun hoá mã điều hướng, hãy làm như sau:
- Tạo hai mô-đun con:
apivàimplcho mỗi tính năng trong ứng dụng - Đặt khoá điều hướng cho từng tính năng vào mô-đun
apicủa tính năng đó - Đặt
entryProvidersvà nội dung có thể điều hướng cho từng tính năng vào mô-đunimplliên quan - Cung cấp
entryProviderscho các mô-đun ứng dụng chính, trực tiếp hoặc sử dụng tính năng chèn phần phụ thuộc
Tách các tính năng thành mô-đun con api và mô-đun con triển khai
Đối với mỗi tính năng trong ứng dụng, hãy tạo hai mô-đun con có tên là api và impl (viết tắt của "implementation" (triển khai)). Hãy sử dụng bảng sau để quyết định vị trí đặt mã điều hướng.
Tên mô-đun |
Chứa |
|
|
|
Nội dung cho tính năng đó, bao gồm cả định nghĩa cho
|
Phương pháp này cho phép một tính năng chuyển đến một tính năng khác bằng cách cho phép nội dung của tính năng đó (có trong mô-đun impl) phụ thuộc vào các khoá điều hướng của một mô-đun khác (có trong mô-đun api của mô-đun đó).
Tách riêng các mục điều hướng bằng hàm mở rộng
Trong Navigation 3, nội dung có thể điều hướng được xác định bằng các mục điều hướng. Để
tách các mục này thành các mô-đun riêng biệt, hãy tạo các hàm mở rộng trên
EntryProviderScope rồi di chuyển các hàm đó vào mô-đun impl cho tính năng đó.
Các trình tạo này được gọi là trình tạo mục nhập.
Ví dụ về mã sau đây cho thấy một trình tạo mục nhập tạo ra hai mục nhập điều hướng.
// import androidx.navigation3.runtime.EntryProviderScope // import androidx.navigation3.runtime.NavKey fun EntryProviderScope<NavKey>.featureAEntryBuilder() { entry<KeyA> { ContentRed("Screen A") { // Content for screen A } } entry<KeyA2> { ContentGreen("Screen A2") { // Content for screen A2 } } }
Gọi hàm đó bằng entryProvider DSL khi xác định entryProvider trong mô-đun ứng dụng chính.
// import androidx.navigation3.runtime.entryProvider // import androidx.navigation3.ui.NavDisplay NavDisplay( entryProvider = entryProvider { featureAEntryBuilder() }, // ... )
Sử dụng tính năng chèn phần phụ thuộc để thêm các mục vào ứng dụng chính
Trong ví dụ về mã trước đó, mỗi trình tạo mục nhập được ứng dụng chính gọi trực tiếp bằng DSL entryProvider. Nếu ứng dụng của bạn có nhiều màn hình hoặc mô-đun tính năng, thì mẫu này có thể không mở rộng được.
Để giải quyết vấn đề này, hãy để mỗi mô-đun tính năng đóng góp trình tạo mục nhập vào hoạt động của ứng dụng bằng cách chèn phần phụ thuộc.
Ví dụ: mã sau đây sử dụng Dagger multibindings, cụ thể là @IntoSet, để chèn trình tạo mục nhập vào Set do MainActivity sở hữu. Sau đó, các hàm này được gọi lặp lại bên trong entryProvider,
loại bỏ nhu cầu gọi rõ ràng nhiều hàm của trình tạo mục nhập.
Mô-đun tính năng
// import dagger.Module // import dagger.Provides // import dagger.hilt.InstallIn // import dagger.hilt.android.components.ActivityRetainedComponent // import dagger.multibindings.IntoSet @Module @InstallIn(ActivityRetainedComponent::class) object FeatureAModule { @IntoSet @Provides fun provideFeatureAEntryBuilder() : EntryProviderScope<NavKey>.() -> Unit = { featureAEntryBuilder() } }
Mô-đun ứng dụng
// import android.os.Bundle // import androidx.activity.ComponentActivity // import androidx.activity.compose.setContent // import androidx.navigation3.runtime.EntryProviderScope // import androidx.navigation3.runtime.NavKey // import androidx.navigation3.runtime.entryProvider // import androidx.navigation3.ui.NavDisplay // import javax.inject.Inject class MainActivity : ComponentActivity() { @Inject lateinit var entryBuilders: Set<@JvmSuppressWildcards EntryProviderScope<NavKey>.() -> Unit> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { NavDisplay( entryProvider = entryProvider { entryBuilders.forEach { builder -> this.builder() } }, // ... ) } } }
Nếu các mục điều hướng cần điều hướng (ví dụ: các mục này chứa các phần tử trên giao diện người dùng điều hướng đến màn hình mới), hãy chèn một đối tượng có khả năng sửa đổi state điều hướng của ứng dụng vào từng hàm của trình tạo.
Mô-đun hoá trình so khớp đường liên kết sâu
Nếu ứng dụng của bạn hỗ trợ đường liên kết sâu và được mô-đun hoá, thì mỗi mô-đun tính năng phải xác định các thực thể DeepLinkMatcher cho đích đến mà mô-đun đó sở hữu.
Để đối chiếu tất cả trình so khớp trong ứng dụng, bạn có thể sử dụng
tính năng liên kết nhiều phần tử chèn phần phụ thuộc. Ví dụ: mỗi mô-đun tính năng có thể đóng góp trình so khớp của mình vào một liên kết đa chiều @IntoSet của Dagger:
Mô-đun tính năng
@Module @InstallIn(ActivityRetainedComponent::class) object FeatureADeepLinkModule { @IntoSet @Provides fun provideUserMatcher(): DeepLinkMatcher<*, *> { return UriDeepLinkMatcher( DeepLinkUri("www.example.com/users/{id}"), serializer<UserProfileKey>() ) } }
Sau đó, trong mô-đun ứng dụng chính, chẳng hạn như trong MainActivity, bạn có thể chèn tập hợp trình so khớp và sử dụng chúng để so khớp các yêu cầu đến:
Mô-đun ứng dụng
@AndroidEntryPoint class MainActivityWithDI : ComponentActivity() { @Inject lateinit var deepLinkMatchers: Set<@JvmSuppressWildcards DeepLinkMatcher<*, *>> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val request = DeepLinkRequest(intent = intent) val matchResult = deepLinkMatchers .mapNotNull { it.match(request) } .maxOrNull() val backStack = when (matchResult) { null -> listOf(HomeKey) is BackStackMatchResult<*, *> -> { @Suppress("UNCHECKED_CAST") matchResult.backStack as List<NavKey> } else -> listOf(matchResult.key) } } }
Để biết thêm thông tin về cách xác định và xử lý đường liên kết sâu, hãy xem phần Hỗ trợ đường liên kết sâu.
Tài nguyên
Để xem các mã mẫu minh hoạ cách mô-đun hoá mã Navigation 3, hãy xem:
- Công thức lập trình cho cấu trúc Navigation 3
- Hành trình tìm hiểu về mô-đun hoá từ ứng dụng Now in Android
- Androidify