Chủ sở hữu trạng thái và Trạng thái giao diện người dùng

Stay organized with collections Save and categorize content based on your preferences.

Hướng dẫn về lớp giao diện người dùng sẽ thảo luận về luồng dữ liệu một chiều (UDF) như một phương tiện để tạo và quản lý Trạng thái giao diện người dùng cho lớp giao diện người dùng.

Dữ liệu di chuyển một chiều từ lớp dữ liệu đến giao diện người dùng.
Hình 1: Luồng dữ liệu một chiều

Hướng dẫn này cũng nêu bật lợi ích của việc uỷ quyền quản lý UDF cho một lớp đặc biệt được gọi là chủ sở hữu trạng thái. Bạn có thể triển khai chủ sở hữu trạng thái thông qua ViewModel hoặc một lớp thuần tuý. Tài liệu này xem xét kỹ hơn các chủ sở hữu trạng thái và vai trò của chúng trong lớp giao diện người dùng.

Ở cuối tài liệu này, bạn sẽ hiểu cách quản lý trạng thái ứng dụng trong lớp giao diện người dùng; đó là quy trình tạo trạng thái giao diện người dùng. Bạn sẽ hiểu và nạp thêm kiến thức dưới đây:

  • Hiểu rõ các loại trạng thái giao diện người dùng tồn tại trong lớp giao diện người dùng.
  • Nắm được nhiều loại logic hoạt động trên các trạng thái giao diện người dùng đó trong lớp giao diện người dùng
  • Biết cách chọn phương thức triển khai phù hợp một chủ sở hữu trạng thái, chẳng hạn như ViewModel hoặc một lớp thuần tuý.

Các thành phần của quy trình tạo trạng thái giao diện người dùng

Trạng thái giao diện người dùng và logic tạo ra trạng thái này xác định lớp giao diện người dùng.

Trạng thái giao diện người dùng

Trạng thái giao diện người dùng là thuộc tính mô tả giao diện người dùng. Có hai loại trạng thái giao diện người dùng:

  • Trạng thái giao diện người dùng màn hìnhnội dung bạn cần hiển thị trên màn hình. Ví dụ như một lớp NewsUiState có thể chứa các bài viết tin tức và những thông tin cần thiết khác để kết xuất giao diện người dùng. Trạng thái này thường được kết nối với các lớp khác trong hệ phân cấp vì nó chứa dữ liệu ứng dụng.
  • Trạng thái thành phần giao diện người dùng đề cập đến các thuộc tính hàm nội tại với các thành phần giao diện người dùng ảnh hưởng đến cách hiển thị các thành phần đó. Một thành phần trên giao diện người dùng có thể hiển thị hoặc ẩn đi, nó đồng thời cũng có một phông chữ, kích thước hoặc màu phông chữ nhất định. Trong Chế độ xem Android, Chế độ xem tự quản lý trạng thái này vì nó vốn có trạng thái, hiển thị các phương thức để sửa đổi hoặc truy vấn trạng thái của nó. Ví dụ như phương thức getset của lớp TextView cho văn bản của lớp đó. Trong Jetpack Compose, trạng thái nằm bên ngoài thành phần kết hợp và bạn thậm chí có thể nâng nó ra khỏi vùng lân cận của thành phần kết hợp vào hàm gọi có thể kết hợp hoặc chủ sở hữu trạng thái. Ví dụ như ScaffoldState cho thành phần kết hợp Scaffold.

Logic

Trạng thái giao diện người dùng không phải là một thuộc tính tĩnh, vì dữ liệu ứng dụng và các sự kiện của người dùng khiến trạng thái giao diện người dùng thay đổi theo thời gian. Logic xác định các chi tiết cụ thể của thay đổi, bao gồm cả những phần của trạng thái giao diện người dùng đã thay đổi, lý do thay đổi và thời điểm thay đổi.

Logic tạo ra trạng thái giao diện người dùng
Hình 2: Logic với tư cách là nhà sản xuất trạng thái giao diện người dùng

Logic này có thể là logic kinh doanh hoặc logic giao diện người dùng:

  • Logic nghiệp vụ là việc triển khai các yêu cầu sản phẩm cho dữ liệu ứng dụng. Ví dụ như đánh dấu một bài viết trong ứng dụng đọc tin tức khi người dùng nhấn vào nút. Logic này để lưu dấu trang vào một tệp hoặc cơ sở dữ liệu thường được đặt trong miền hoặc lớp dữ liệu. Chủ sở hữu trạng thái thường uỷ quyền logic này cho các lớp đó bằng cách gọi phương thức mà các lớp này hiển thị.
  • Logic giao diện người dùng liên quan đến cách hiện trạng thái giao diện người dùng trên màn hình. Ví dụ như nhận được gợi ý về thanh tìm kiếm phù hợp khi người dùng đã chọn một danh mục, cuộn đến một mục cụ thể trong danh sách hoặc logic điều hướng đến một màn hình cụ thể khi người dùng nhấp vào một nút.

Vòng đời của Android cũng như các loại trạng thái và logic của giao diện người dùng

Lớp giao diện người dùng có hai phần: một phần phụ thuộc và phần còn lại độc lập với vòng đời của giao diện người dùng. Việc phân tách này xác định các nguồn dữ liệu có sẵn cho từng phần, do đó yêu cầu nhiều loại trạng thái và logic của giao diện người dùng.

  • Vòng đời của giao diện người dùng độc lập: Phần này của lớp giao diện người dùng xử lý các lớp tạo dữ liệu của ứng dụng (lớp dữ liệu hoặc lớp miền), đồng thời được xác định theo logic kinh doanh. Vòng đời, thay đổi về cấu hình và hoạt động tạo lại Activity trong giao diện người dùng có thể ảnh hưởng nếu quy trình tạo trạng thái giao diện người dùng đang hoạt động, nhưng không ảnh hưởng đến tính hợp lệ của dữ liệu được tạo.
  • Phần phụ thuộc của vòng đời giao diện người dùng: Phần này của lớp giao diện người dùng xử lý logic giao diện người dùng, đồng thời chịu ảnh hưởng trực tiếp của các thay đổi về vòng đời hoặc cấu hình. Những thay đổi này trực tiếp ảnh hưởng đến tính hợp lệ của các nguồn dữ liệu được đọc trong đó, và do đó, trạng thái của nó chỉ có thể thay đổi khi vòng đời đang hoạt động. Ví dụ về vấn đề này bao gồm các quyền khi bắt đầu chạy và nhận tài nguyên phụ thuộc vào cấu hình, chẳng hạn như các chuỗi đã được bản địa hoá.

Bạn có thể xem bản tóm tắt ở trên qua bảng dưới đây:

Vòng đời của giao diện người dùng độc lập Phần phụ thuộc vào Vòng đời giao diện người dùng
Logic kinh doanh Logic giao diện người dùng
Trạng thái giao diện người dùng trên màn hình

Quy trình tạo trạng thái giao diện người dùng

Quy trình tạo trạng thái giao diện người dùng là các bước được thực hiện để tạo trạng thái giao diện người dùng. Các bước này bao gồm việc áp dụng các loại logic được xác định trước đó, và hoàn toàn phụ thuộc vào nhu cầu của giao diện người dùng. Một số giao diện người dùng có thể hưởng lợi từ cả phần phụ thuộc Vòng đời giao diện người dùng lẫn phần phụ thuộc Vòng đời giao diện người dùng của quy trình, hoặc cả hai hoặc không.

Điều đó có nghĩa là các phép hoán vị sau của quy trình lớp giao diện người dùng hợp lệ:

  • Trạng thái giao diện người dùng do chính giao diện người dùng tạo ra và quản lý. Ví dụ, một bộ đếm cơ bản đơn giản và có thể tái sử dụng:

    @Composable
    fun Counter() {
        // The UI state is managed by the UI itself
        var count by remember { mutableStateOf(0) }
        Row {
            Button(onClick = { ++count }) {
                Text(text = "Increment")
            }
            Button(onClick = { --count }) {
                Text(text = "Decrement")
            }
        }
    }
    
  • Logic giao diện người dùng → giao diện người dùng. Ví dụ: hiện hoặc ẩn nút cho phép người dùng chuyển lên đầu danh sách.

    @Composable
    fun ContactsList(contacts: List<Contact>) {
        val listState = rememberLazyListState()
        val isAtTopOfList by remember {
            derivedStateOf {
                listState.firstVisibleItemIndex < 3
            }
        }
    
        // Create the LazyColumn with the lazyListState
        ...
    
        // Show or hide the button (UI logic) based on the list scroll position
        AnimatedVisibility(visible = !isAtTopOfList) {
            ScrollToTopButton()
        }
    }
    
  • Logic kinh doanh → giao diện người dùng. Một thành phần trên giao diện người dùng hiển thị ảnh của người dùng hiện tại trên màn hình.

    @Composable
    fun UserProfileScreen(viewModel: UserProfileViewModel = hiltViewModel()) {
        // Read screen UI state from the business logic state holder
        val uiState by viewModel.uiState.collectAsStateWithLifecycle()
    
        // Call on the UserAvatar Composable to display the photo
        UserAvatar(picture = uiState.profilePicture)
    }
    
  • Logic kinh doanh → logic giao diện người dùng → giao diện người dùng. Một thành phần trên giao diện người dùng cuộn để hiển thị thông tin phù hợp trên màn hình cho một trạng thái giao diện người dùng nhất định.

    @Composable
    fun ContactsList(viewModel: ContactsViewModel = hiltViewModel()) {
        // Read screen UI state from the business logic state holder
        val uiState by viewModel.uiState.collectAsStateWithLifecycle()
        val contacts = uiState.contacts
        val deepLinkedContact = uiState.deepLinkedContact
    
        val listState = rememberLazyListState()
    
        // Create the LazyColumn with the lazyListState
        ...
    
        // Perform UI logic that depends on information from business logic
        if (deepLinkedContact != null && contacts.isNotEmpty()) {
            LaunchedEffect(listState, deepLinkedContact, contacts) {
                val deepLinkedContactIndex = contacts.indexOf(deepLinkedContact)
                if (deepLinkedContactIndex >= 0) {
                  // Scroll to deep linked item
                  listState.animateScrollToItem(deepLinkedContactIndex)
                }
            }
        }
    }
    

Trong trường hợp cả hai loại logic cho quy trình tạo trạng thái giao diện người dùng được áp dụng, logic kinh doanh phải luôn được áp dụng trước logic giao diện người dùng. Việc cố gắng áp dụng logic kinh doanh sau logic giao diện người dùng sẽ ngụ ý logic kinh doanh đó phụ thuộc vào logic giao diện người dùng. Các phần sau đây trình bày lý do khiến đây là một vấn đề thông qua việc tìm hiểu sâu về các loại logic khác nhau và chủ sở hữu trạng thái của các loại đó.

Dữ liệu di chuyển từ lớp tạo dữ liệu sang giao diện người dùng
Hình 3: Áp dụng logic trong lớp giao diện người dùng

Chủ sở hữu trạng thái và trách nhiệm của chúng

Trách nhiệm của chủ sở hữu trạng thái là lưu trữ trạng thái để ứng dụng có thể đọc. Trong trường hợp cần logic, logic đó đóng vai trò là bên trung gian cung cấp quyền truy cập vào các nguồn dữ liệu lưu trữ logic cần thiết. Qua đó, chủ sở hữu trạng thái sẽ uỷ quyền logic cho nguồn dữ liệu thích hợp.

Điều này mang lại các lợi ích sau:

  • Giao diện người dùng đơn giản: Giao diện người dùng chỉ liên kết với trạng thái của nó.
  • Khả năng bảo trì: Logic xác định trong chủ sở hữu trạng thái có thể lặp lại mà không cần thay đổi chính giao diện người dùng.
  • Khả năng thử nghiệm: Giao diện người dùng và logic tạo trạng thái có thể được kiểm thử một cách độc lập.
  • Tính dễ đọc: Người đọc mã có thể thấy rõ sự khác biệt giữa mã trình bày giao diện người dùng và mã tạo trạng thái giao diện người dùng.

Dù với bất kỳ kích thước hoặc phạm vi nào, mọi thành phần giao diện người dùng cũng đều có mối quan hệ 1:1 với chủ sở hữu trạng thái tương ứng. Hơn nữa, chủ sở hữu trạng thái phải có khả năng chấp nhận và xử lý mọi hành động của người dùng có thể dẫn đến sự thay đổi trạng thái trên giao diện người dùng, đồng thời phải tạo ra các thay đổi trạng thái tiếp theo.

Các loại chủ sở hữu trạng thái

Tương tự như các kiểu trạng thái và logic của giao diện người dùng, có hai loại chủ sở hữu trạng thái trong lớp giao diện người dùng được xác định theo mối quan hệ của chúng với vòng đời của giao diện người dùng:

  • Chủ sở hữu trạng thái logic kinh doanh.
  • Chủ sở hữu trạng thái logic của giao diện người dùng.

Phần sau sẽ tìm hiểu kỹ hơn về các loại chủ sở hữu trạng thái, bắt đầu từ chủ sở hữu trạng thái logic kinh doanh.

Logic kinh doanh và chủ sở hữu trạng thái của nó

Chủ sở hữu trạng thái logic kinh doanh xử lý sự kiện của người dùng và biến đổi dữ liệu từ các lớp dữ liệu hoặc lớp miền sang trạng thái giao diện người dùng màn hình. Nhằm cung cấp trải nghiệm người dùng tối ưu khi xem xét vòng đời của Android và các thay đổi về cấu hình ứng dụng, chủ sở hữu trạng thái sử dụng logic kinh doanh phải có các thuộc tính sau:

Thuộc tính Chi tiết
Tạo trạng thái giao diện người dùng Chủ sở hữu trạng thái logic kinh doanh chịu trách nhiệm tạo trạng thái giao diện người dùng cho giao diện người dùng của chúng. Trạng thái giao diện người dùng này thường là kết quả của quá trình xử lý sự kiện người dùng và đọc dữ liệu từ miền và các lớp dữ liệu.
Được giữ lại thông qua quá trình tạo lại hoạt động Chủ sở hữu trạng thái logic kinh doanh giữ lại quy trình xử lý trạng thái và trạng thái của chúng trong quá trình tạo lại Activity, giúp cung cấp trải nghiệm người dùng liền mạch. Trong trường hợp không thể giữ và tạo lại chủ sở hữu trạng thái (thường là sau khi quá trình bị gián đoạn), thì chủ sở hữu trạng thái phải có thể dễ dàng tạo lại trạng thái gần đây nhất để đảm bảo trải nghiệm nhất quán cho người dùng.
Sở hữu các trạng thái tồn tại lâu Chủ sở hữu trạng thái logic kinh doanh thường được dùng để quản lý trạng thái của các đích điều hướng. Do đó, chúng thường giữ nguyên trạng thái trên các thay đổi điều hướng cho đến khi bị xoá khỏi biểu đồ điều hướng.
Là duy nhất cho giao diện người dùng và không thể sử dụng lại Chủ sở hữu trạng thái logic kinh doanh thường tạo trạng thái cho một chức năng của ứng dụng nhất định, chẳng hạn như TaskEditViewModel hoặc TaskListViewModel, và do đó chỉ áp dụng cho chức năng của ứng dụng đó. Chủ sở hữu trạng thái đó có thể hỗ trợ các chức năng của ứng dụng này trên nhiều hệ số hình dạng. Ví dụ như các phiên bản dành cho thiết bị di động, TV và máy tính bảng của ứng dụng có thể sử dụng lại cùng một chủ sở hữu trạng thái logic kinh doanh.

Ví dụ như hãy xem xét đích đến điều hướng của tác giả trong ứng dụng "Now in Android":

Ứng dụng Now in Android minh hoạ cách một đích đến điều hướng đại diện cho một chức năng của ứng dụng chính phải có chủ sở hữu trạng thái logic kinh doanh riêng.
Hình 4: Ứng dụng Now in Android

Với vai trò là chủ sở hữu trạng thái logic kinh doanh, AuthorViewModel sẽ tạo ra trạng thái giao diện người dùng trong trường hợp sau:

@HiltViewModel
class AuthorViewModel @Inject constructor(
    savedStateHandle: SavedStateHandle,
    private val authorsRepository: AuthorsRepository,
    newsRepository: NewsRepository
) : ViewModel() {

    val uiState: StateFlow<AuthorScreenUiState> = …

    // Business logic
    fun followAuthor(followed: Boolean) {
      …
    }
}

Lưu ý là AuthorViewModel có các thuộc tính đã nêu trước đây:

Thuộc tính Chi tiết
Tạo AuthorScreenUiState AuthorViewModel đọc dữ liệu từ AuthorsRepositoryNewsRepository, đồng thời sử dụng dữ liệu đó để tạo AuthorScreenUiState. Hoạt động này cũng áp dụng logic kinh doanh khi người dùng muốn theo dõi hoặc huỷ theo dõi Author bằng cách uỷ quyền cho AuthorsRepository.
Có quyền truy cập vào lớp dữ liệu Một thực thể của AuthorsRepositoryNewsRepository đã được truyền vào thực thể trong hàm khởi tạo, cho phép thực hiện logic kinh doanh của việc tuân theo Author.
Việc tạo lại Activity tiếp tục có hiệu lực Vì được triển khai bằng ViewModel, thuộc tính này sẽ được giữ lại qua việc tạo lại nhanh Activity. Trong trường hợp quá trình bị gián đoạn, đối tượng SavedStateHandle có thể được đọc để cung cấp lượng thông tin tối thiểu cần thiết để khôi phục trạng thái giao diện người dùng từ lớp dữ liệu.
Sở hữu trạng thái tồn tại lâu ViewModel nằm trong phạm vi của biểu đồ điều hướng, do đó, trừ khi đích tác giả bị xoá khỏi biểu đồ điều hướng, trạng thái giao diện người dùng trong uiState StateFlow vẫn còn trong bộ nhớ. Việc sử dụng StateFlow cũng bổ sung lợi ích của việc áp dụng logic kinh doanh tạo ra trạng thái tải lười, vì trạng thái chỉ được tạo nếu có một trình thu thập trạng thái giao diện người dùng.
Là duy nhất cho giao diện người dùng AuthorViewModel chỉ áp dụng cho đích đến điều hướng tác giả và không thể sử dụng lại ở bất kỳ nơi nào khác. Nếu có bất kỳ logic kinh doanh nào được sử dụng lại trên các đích điều hướng, thì logic kinh doanh đó phải được gói gọn trong thành phần phạm vi lớp dữ liệu hoặc phạm vi lớp miền.

ViewModel với tư cách là chủ sở hữu trạng thái logic kinh doanh

Lợi ích của ViewModel trong quá trình phát triển Android là giúp các ứng dụng này phù hợp với việc cung cấp quyền truy cập vào logic kinh doanh và chuẩn bị dữ liệu ứng dụng để hiển thị trên màn hình. Các lợi ích này bao gồm:

  • Những hoạt động kích hoạt bởi ViewModel vẫn tồn tại sau những thay đổi về cấu hình.
  • Tích hợp với Điều hướng (Navigation):
    • Thao tác sẽ lưu các ViewModel vào bộ nhớ đệm trong khi màn hình đang ở ngăn xếp lui. Việc cung cấp dữ liệu được tải trước đó ngay lập tức khi bạn quay lại đích là rất quan trọng. Đây là một vấn đề khó thực hiện hơn với chủ sở hữu trạng thái theo dõi vòng đời của màn hình thành phần kết hợp.
    • ViewModel cũng bị xoá khi điểm đến được bật ra khỏi ngăn xếp lui, đảm bảo trạng thái của bạn được tự động dọn dẹp. Điều này khác với trình nghe loại bỏ thành phần kết hợp có thể xảy ra vì nhiều lý do, chẳng hạn như khi chuyển sang màn hình mới, do thay đổi về cấu hình, v.v.
  • Tích hợp với các thư viện Jetpack khác như Hilt.

Logic giao diện người dùng và chủ sở hữu trạng thái của nó

Logic giao diện người dùng là logic hoạt động trên dữ liệu mà chính giao diện người dùng cung cấp. Trạng thái này có thể ở trạng thái của các thành phần trên giao diện người dùng, hoặc trên các nguồn dữ liệu giao diện người dùng như API về quyền hoặc Resources. Các chủ sở hữu trạng thái sử dụng logic giao diện người dùng thường có các thuộc tính sau:

  • Tạo trạng thái giao diện người dùng và quản lý trạng thái các thành phần giao diện người dùng.
  • Không tồn tại Activity tạo lại: Các chủ sở hữu trạng thái được lưu trữ trong logic giao diện người dùng thường phụ thuộc vào các nguồn dữ liệu từ chính giao diện người dùng, và cố gắng giữ lại thông tin này qua các thay đổi về cấu hình thường xuyên hơn không gây ra sự cố rò rỉ bộ nhớ. Nếu chủ sở hữu trạng thái cần dữ liệu để duy trì các thay đổi về cấu hình, thì chúng cần được uỷ quyền cho một thành phần khác phù hợp hơn để tiếp tục tạo lại Activity. Ví dụ như trong Jetpack Compose, các trạng thái thành phần giao diện người dùng có thể kết hợp được tạo bằng các hàm remembered, thường uỷ quyền cho rememberSaveable để duy trì trạng thái trên quá trình tạo lại Activity. Ví dụ về các hàm này bao gồm rememberScaffoldState()rememberLazyListState().
  • Có thông tin tham chiếu đến các nguồn dữ liệu trong phạm vi giao diện người dùng: Các nguồn dữ liệu như API vòng đời và Tài nguyên có thể được tham chiếu và đọc một cách an toàn, vì chủ sở hữu trạng thái logic của giao diện người dùng có cùng vòng đời với giao diện người dùng.
  • Có thể sử dụng lại trên nhiều giao diện người dùng: Có thể sử dụng lại các phiên bản khác nhau của cùng một chủ sở hữu trạng thái logic giao diện người dùng trong các phần khác nhau của ứng dụng. Ví dụ như chủ sở hữu trạng thái, để quản lý các sự kiện nhập của người dùng cho một nhóm chip có thể được dùng trên trang tìm kiếm các thẻ bộ lọc, và cho trường "tới" của người nhận email.

Chủ sở hữu trạng thái logic của giao diện người dùng thường được triển khai bằng một lớp thuần tuý. Điều này là do giao diện người dùng tự chịu trách nhiệm về việc tạo chủ sở hữu trạng thái logic giao diện người dùng, và nó có cùng vòng đời với giao diện người dùng. Ví dụ như trong Jetpack Compose, chủ sở hữu trạng thái là một phần của Thành phần cấu tạo và tuân theo vòng đời của Thành phần cấu tạo.

Điều này được minh hoạ ở ví dụ sau trong mẫu ứng dụng Now in Android:

Ứng dụng Now in Android sử dụng chủ sở hữu trạng thái của lớp thuần tuý để quản lý logic giao diện người dùng
Hình 5: Ứng dụng mẫu Now in Android

Mẫu ứng dụng Now in Android cho thấy thanh ứng dụng ở dưới cùng hoặc thanh điều hướng của nó tuỳ thuộc vào kích thước màn hình của thiết bị. Màn hình nhỏ hơn sử dụng thanh ứng dụng ở dưới cùng, còn màn hình lớn hơn sử dụng dải điều hướng.

Vì logic để quyết định thành phần trên giao diện người dùng điều hướng thích hợp được sử dụng trong hàm kết hợp NiaApp không phụ thuộc vào logic kinh doanh, nênhàm này có thể được quản lý bằng một chủ sở hữu trạng thái của lớp thuần tuý có tên là NiaAppState:

@Stable
class NiaAppState(
    val navController: NavHostController,
    val windowSizeClass: WindowSizeClass
) {

    // UI logic
    val shouldShowBottomBar: Boolean
        get() = windowSizeClass.widthSizeClass == WindowWidthSizeClass.Compact ||
            windowSizeClass.heightSizeClass == WindowHeightSizeClass.Compact

    // UI logic
    val shouldShowNavRail: Boolean
        get() = !shouldShowBottomBar

   // UI State
    val currentDestination: NavDestination?
        @Composable get() = navController
            .currentBackStackEntryAsState().value?.destination

    // UI logic
    fun navigate(destination: NiaNavigationDestination, route: String? = null) { /* ... */ }

     /* ... */
}

Trong ví dụ trên, bạn nên chú ý những thông tin chi tiết sau đây về NiaAppState:

  • Không tồn tại Activity tạo lại : NiaAppState được remembered trong Thành phần cấu tạo bằng cách tạo nó với một Hàm có khả năng kết hợp rememberNiaAppState tuân theo quy ước đặt tên của Compose. Sau khi tạo lại Activity, bản sao trước đó sẽ bị mất và một bản sao mới được tạo với tất cả các phần phụ thuộc được truyền vào, phù hợp với cấu hình mới của Activity được tạo lại. Những phần phụ thuộc này có thể mới hoặc được khôi phục từ cấu hình trước đó. Chẳng hạn như rememberNavController() được sử dụng trong hàm khởi tạo NiaAppState và uỷ quyền cho rememberSaveable để duy trì trạng thái trong quá trình tái tạo Activity.
  • Có tệp tham chiếu đến các nguồn dữ liệu trong phạm vi giao diện người dùng: Tham chiếu đến navigationController, Resources và các loại phạm vi vòng đời tương tự khác có thể được giữ an toàn trong NiaAppState vì chúng có cùng phạm vi vòng đời.

Chọn giữa ViewModel và lớp đơn giản cho chủ sở hữu trạng thái

Từ các phần đã nói ở trên, việc lựa chọn giữa ViewModel và chủ sở hữu trạng thái của lớp đơn giản sẽ dẫn đến logic được áp dụng cho trạng thái giao diện người dùng và các nguồn dữ liệu mà logic hoạt động.

Tóm lại, sơ đồ dưới đây cho thấy vị trí của chủ sở hữu trạng thái trong quy trình tạo trạng thái của giao diện người dùng:

Dữ liệu di chuyển từ lớp tạo dữ liệu sang lớp giao diện người dùng
Hình 6: Các chủ sở hữu trạng thái trong quy trình tạo trạng thái giao diện người dùng

Cuối cùng, bạn phải đặt và tạo trạng thái giao diện người dùng từ các chủ sở hữu trạng thái gần nhất với vị trí trạng thái đó được sử dụng.. Nói một cách đơn giản hơn, trạng thái phải ở mức thấp nhất có thể trong khi vẫn được sở hữu đúng cách. Nếu bạn cần quyền truy cập vào logic nghiệp vụ và cần trạng thái giao diện người dùng duy trì miễn là màn hình có thể được di chuyển đến, thậm chí trong quá trình tạo lại Activity, ViewModel là lựa chọn tuyệt vời cho việc triển khai chủ sở hữu trạng thái logic nghiệp vụ của bạn. Đối với trạng thái giao diện người dùng tồn tại ngắn hơn và logic giao diện người dùng, bạn chỉ nên sử dụng một lớp đơn giản có vòng đời duy nhất dựa trên giao diện người dùng là đủ.