Đóng gói mã điều hướng của bạn

Khi sử dụng Kotlin DSL để tạo biểu đồ, việc duy trì các đích đến và sự kiện điều hướng trong một tệp có thể khó duy trì. Điều này đặc biệt đúng nếu bạn có nhiều tính năng độc lập.

Trích xuất đích đến

Bạn nên di chuyển đích đến vào các hàm tiện ích NavGraphBuilder. Các lớp này phải nằm ở gần các tuyến xác định và màn hình mà các tuyến đó hiển thị. Ví dụ: hãy xem xét mã cấp ứng dụng sau đây tạo một đích đến hiển thị danh sách liên hệ:

// MyApp.kt

@Serializable
object Contacts

@Composable
fun MyApp() {
  ...
  NavHost(navController, startDestination = Contacts) {
    composable<Contacts> { ContactsScreen( /* ... */ ) }
  }
}

Bạn nên di chuyển mã dành riêng cho điều hướng vào một tệp riêng:

// ContactsNavigation.kt

@Serializable
object Contacts

fun NavGraphBuilder.contactsDestination() {
    composable<Contacts> { ContactsScreen( /* ... */ ) }
}

// MyApp.kt

@Composable
fun MyApp() {
  ...
  NavHost(navController, startDestination = Contacts) {
     contactsDestination()
  }
}

Các tuyến và định nghĩa đích đến hiện tách biệt với ứng dụng chính và bạn có thể cập nhật chúng một cách độc lập. Ứng dụng chính chỉ phụ thuộc vào một chức năng tiện ích duy nhất. Trong trường hợp này, đó là NavGraphBuilder.contactsDestination().

Hàm tiện ích NavGraphBuilder tạo thành cầu nối giữa hàm có khả năng kết hợp cấp màn hình không có trạng thái và logic Điều hướng cụ thể. Lớp này cũng có thể xác định nguồn gốc của trạng thái và cách bạn xử lý các sự kiện.

Ví dụ

Đoạn mã sau đây giới thiệu một đích đến mới để hiển thị thông tin chi tiết về một liên hệ và cập nhật đích đến hiện có của danh bạ đó để hiển thị một sự kiện điều hướng nhằm hiển thị thông tin chi tiết của người liên hệ đó.

Sau đây là một nhóm màn hình thông thường, có thể là internal đối với mô-đun riêng để các mô-đun khác không thể truy cập vào đó:

// ContactScreens.kt

// Displays a list of contacts
@Composable
internal fun ContactsScreen(
  uiState: ContactsUiState,
  onNavigateToContactDetails: (contactId: String) -> Unit
) { ... }

// Displays the details for an individual contact
@Composable
internal fun ContactDetailsScreen(contact: ContactDetails) { ... }

Tạo đích đến

Hàm tiện ích NavGraphBuilder sau đây sẽ tạo một đích đến hiển thị thành phần kết hợp ConversationScreen. Ngoài ra, mã này hiện còn kết nối màn hình với một ViewModel cung cấp trạng thái giao diện người dùng màn hình và xử lý logic nghiệp vụ liên quan đến màn hình.

Các sự kiện điều hướng, chẳng hạn như di chuyển tới đích đến thông tin liên hệ, sẽ hiển thị cho phương thức gọi thay vì được ViewModel xử lý.

// ContactsNavigation.kt

@Serializable
object Contacts

// Adds contacts destination to `this` NavGraphBuilder
fun NavGraphBuilder.contactsDestination(
  // Navigation events are exposed to the caller to be handled at a higher level
  onNavigateToContactDetails: (contactId: String) -> Unit
) {
  composable<Contacts> {
    // The ViewModel as a screen level state holder produces the screen
    // UI state and handles business logic for the ConversationScreen
    val viewModel: ContactsViewModel = hiltViewModel()
    val uiState = viewModel.uiState.collectAsStateWithLifecycle()
    ContactsScreen(
      uiState,
      onNavigateToContactDetails
    )
  }
}

Bạn có thể sử dụng phương pháp tương tự để tạo đích đến hiển thị ContactDetailsScreen. Trong trường hợp này, thay vì lấy trạng thái giao diện người dùng từ mô hình chế độ xem, bạn có thể lấy trạng thái trực tiếp từ NavBackStackEntry.

// ContactsNavigation.kt

@Serializable
internal data class ContactDetails(val id: String)

fun NavGraphBuilder.contactDetailsScreen() {
  composable<ContactDetails> { navBackStackEntry ->
    ContactDetailsScreen(contact = navBackStackEntry.toRoute())
  }
}

Đóng gói sự kiện điều hướng

Tương tự như cách đóng gói đích đến, bạn có thể đóng gói các sự kiện điều hướng để tránh để lộ các loại tuyến một cách không cần thiết. Hãy thực hiện việc này bằng cách tạo các hàm mở rộng trên NavController.

// ContactsNavigation.kt

fun NavController.navigateToContactDetails(id: String) {
  navigate(route = ContactDetails(id = id))
}

Kết hợp

Mã điều hướng để hiển thị danh bạ hiện được tách biệt rõ ràng với biểu đồ điều hướng của ứng dụng. Ứng dụng cần:

  • Gọi các hàm mở rộng NavGraphBuilder để tạo đích đến
  • Kết nối các đích đến đó bằng cách gọi hàm mở rộng NavController cho các sự kiện điều hướng
// MyApp.kt

@Composable
fun MyApp() {
  ...
  NavHost(navController, startDestination = Contacts) {
     contactsDestination(onNavigateToContactDetails = { contactId ->
        navController.navigateToContactDetails(id = contactId)
     })
     contactDetailsDestination()
  }
}

Tóm tắt

  • Đóng gói mã điều hướng của bạn cho một nhóm màn hình có liên quan bằng cách đặt mã đó trong một tệp riêng
  • Hiển thị đích đến bằng cách tạo các hàm mở rộng trên NavGraphBuilder
  • Hiển thị các sự kiện điều hướng bằng cách tạo các hàm mở rộng trên NavController
  • Dùng internal để bảo mật màn hình và loại tuyến