Compose coi các loại là ổn định hoặc không ổn định. Một loại được coi là ổn định nếu đó là loại bất biến hoặc nếu Compose có thể xác định liệu giá trị của thành phần đó có thay đổi giữa các lần kết hợp lại hay không. Một loại được coi là không ổn định nếu Compose không thể xác định liệu giá trị của thành phần đó có thay đổi giữa các lần kết hợp lại hay không.
Compose sử dụng độ ổn định của các tham số của thành phần kết hợp để xác định cách so sánh các đầu vào và quyết định xem có thể bỏ qua thành phần kết hợp trong quá trình tái kết hợp hay không (với Chế độ bỏ qua mạnh được bật theo mặc định bắt đầu từ Kotlin 2.0.20):
- Tham số ổn định: Compose so sánh các tham số ổn định bằng cách sử dụng sự cân bằng về cấu trúc (
Object.equals()). Nếu các tham số ổn định của một thành phần kết hợp bằng với các giá trị trước đó, thì Compose sẽ bỏ qua thành phần đó. - Tham số không ổn định: Khi bạn bật Chế độ bỏ qua hữu hiệu (mặc định trong Kotlin 2.0.20 trở lên), Compose sẽ so sánh các tham số không ổn định bằng cách sử dụng sự cân bằng về thực thể (
===) và bỏ qua thành phần kết hợp nếu cùng một thực thể đối tượng được truyền. Trong các phiên bản trước Kotlin 2.0.20 (hoặc khi bạn tắt chế độ Bỏ qua hữu hiệu), Compose luôn kết hợp lại một thành phần kết hợp có các tham số không ổn định khi thành phần mẹ kết hợp lại.
Nếu ứng dụng của bạn thường xuyên phân bổ các thực thể mới của các tham số không ổn định hoặc buộc các lượt kiểm tra .equals() tốn kém trên các bộ sưu tập lớn bằng cách chú thích quá nhiều mô hình, thì bạn có thể thấy các thành phần kết hợp lại không cần thiết hoặc chi phí so sánh.
Tài liệu này trình bày chi tiết cách Compose xác định độ ổn định và cách bạn có thể tối ưu hoá độ ổn định để cải thiện hiệu suất cũng như trải nghiệm tổng thể của người dùng.
Đối tượng không thể thay đổi
Các đoạn mã sau đây minh hoạ các nguyên tắc chung đằng sau tính ổn định và việc kết hợp lại.
Lớp Contact là một lớp dữ liệu không thể thay đổi. Nguyên nhân là do tất cả các tham số của nó đều là các kiểu dữ liệu nguyên thuỷ được xác định bằng từ khoá val. Sau khi tạo một thực thể của Contact, bạn không thể thay đổi giá trị của các thuộc tính của đối tượng.
Nếu cố gắng làm như vậy, bạn sẽ tạo một đối tượng mới.
data class Contact(val name: String, val number: String)
Thành phần kết hợp ContactRow có một tham số thuộc loại Contact.
@Composable
fun ContactRow(contact: Contact, modifier: Modifier = Modifier) {
var selected by remember { mutableStateOf(false) }
Row(modifier) {
ContactDetails(contact)
ToggleButton(selected, onToggled = { selected = !selected })
}
}
Hãy xem xét điều gì sẽ xảy ra khi người dùng nhấp vào nút bật tắt và trạng thái selected thay đổi:
- Compose đánh giá xem có nên kết hợp lại mã bên trong
ContactRowhay không. - Nó thấy rằng đối số duy nhất cho
ContactDetailsthuộc loạiContact. - Vì
Contactlà một lớp dữ liệu bất biến, nên Compose chắc chắn rằng không có đối số nào choContactDetailsthay đổi. - Do đó, Compose bỏ qua
ContactDetailsvà không kết hợp lại thành phần này. - Mặt khác, các đối số cho
ToggleButtonđã thay đổi và Compose sẽ kết hợp lại thành phần đó.
Đối tượng có thể thay đổi
Mặc dù ví dụ trước sử dụng một đối tượng không thể thay đổi, nhưng bạn có thể tạo một đối tượng có thể thay đổi. Hãy xem xét đoạn mã sau:
data class Contact(var name: String, var number: String)
Vì mỗi tham số của Contact hiện là một var, nên lớp này không còn bất biến nữa.
Nếu các thuộc tính của nó thay đổi, Compose sẽ không nhận biết được. Lý do là vì Compose chỉ theo dõi các thay đổi đối với đối tượng State của Compose.
Compose coi lớp như vậy là không ổn định. Với Chế độ bỏ qua mạnh mẽ (Kotlin 2.0.20 trở lên), Compose so sánh Contact bằng cách sử dụng tính năng so sánh thực thể (===): việc thay đổi contact.name tại chỗ sẽ không kích hoạt quá trình kết hợp lại, trong khi việc truyền một thực thể Contact mới được phân bổ có giá trị giống hệt nhau vẫn sẽ buộc ContactDetails kết hợp lại (và nếu không có Chế độ bỏ qua mạnh mẽ, ContactDetails sẽ kết hợp lại mỗi khi selected thay đổi).
Triển khai trong Compose
Bạn nên cân nhắc (nhưng không bắt buộc) cách Compose xác định chính xác những hàm cần bỏ qua trong quá trình kết hợp lại.
Khi chạy trên mã của bạn, trình biên dịch Compose sẽ đánh dấu từng hàm và loại bằng một trong số các thẻ. Các thẻ này phản ánh cách Compose xử lý hàm hoặc loại trong quá trình kết hợp lại.
Hàm
Compose có thể đánh dấu các hàm là skippable hoặc restartable. Xin lưu ý rằng bạn có thể đánh dấu một hàm là một, cả hai hoặc không có hàm nào trong số này:
- Có thể bỏ qua: Nếu trình biên dịch đánh dấu một thành phần kết hợp là có thể bỏ qua, thì Compose có thể bỏ qua thành phần đó trong quá trình kết hợp lại nếu tất cả các đối số của thành phần đó đều bằng với các giá trị trước đó. (Với Chế độ bỏ qua hữu hiệu trong Kotlin 2.0.20 trở lên, tất cả các thành phần kết hợp có thể khởi động lại đều tự động bỏ qua được.)
- Có thể khởi động lại: Thành phần kết hợp có thể khởi động lại đóng vai trò là một "phạm vi" nơi có thể bắt đầu kết hợp lại. Nói cách khác, hàm này có thể là điểm truy cập để Compose có thể bắt đầu thực thi lại mã cho quá trình kết hợp lại sau khi trạng thái thay đổi.
Loại
Compose đánh dấu các kiểu là không thay đổi hoặc ổn định. Mỗi loại là một hoặc loại khác:
- Không thể thay đổi: Compose đánh dấu một loại là không thể thay đổi nếu giá trị của các thuộc tính không bao giờ thay đổi và tất cả các phương thức đều trong suốt về mặt tham chiếu.
- Xin lưu ý rằng tất cả các kiểu nguyên thuỷ đều được đánh dấu là không thể thay đổi. Các API này bao gồm
String,IntvàFloat.
- Xin lưu ý rằng tất cả các kiểu nguyên thuỷ đều được đánh dấu là không thể thay đổi. Các API này bao gồm
- Ổn định: Cho biết một kiểu có các thuộc tính có thể thay đổi sau khi tạo. Nếu và khi những thuộc tính đó thay đổi trong thời gian chạy, Compose sẽ nhận biết được những thay đổi đó.
Độ ổn định gỡ lỗi
Nếu ứng dụng của bạn đang recomposition một composable có các tham số không thay đổi, trước tiên, hãy kiểm tra xem các thực thể mới của các loại không ổn định có đang được phân bổ trên mọi lần recomposition hay không (hoặc, nếu Chế độ bỏ qua mạnh bị vô hiệu hoá, hãy kiểm tra xem composable có các tham số có thuộc tính var hay thuộc tính val của một loại không ổn định hay không).
Để biết thông tin chi tiết về cách chẩn đoán các vấn đề phức tạp về tính ổn định trong Compose, hãy xem hướng dẫn Gỡ lỗi tính ổn định.
Khắc phục vấn đề về độ ổn định
Để biết thông tin về cách làm cho quá trình triển khai Compose trở nên ổn định, hãy xem hướng dẫn Khắc phục sự cố về tính ổn định.
Tóm tắt
Nhìn chung, bạn nên lưu ý những điểm sau:
- Tham số: Compose xác định độ ổn định của từng tham số trong thành phần kết hợp để quyết định có so sánh các tham số đó bằng cách sử dụng sự cân bằng về cấu trúc (
.equals()) hay sự cân bằng về thực thể (===) trong quá trình kết hợp lại hay không. - Khắc phục ngay: Nếu bạn nhận thấy composable của mình không bị bỏ qua và điều này gây ra vấn đề về hiệu suất, hãy kiểm tra xem các thực thể mới của những tham số không ổn định có đang được tạo lại trên mỗi lượt truyền hay không hoặc liệu các thuộc tính
varcó đang được dùng thay vìStatehay không. - Báo cáo của trình biên dịch: Bạn có thể sử dụng báo cáo của trình biên dịch để xác định mức độ ổn định được suy luận về các lớp của bạn.
- Tập hợp: Compose coi các giao diện tập hợp tiêu chuẩn (
List,SetvàMap) là không ổn định vì các phương thức triển khai cơ bản của chúng có thể thay đổi. Với Chế độ bỏ qua mạnh (được bật theo mặc định trong Kotlin 2.0.20 trở lên), các tập hợp không ổn định vẫn bỏ qua quá trình recomposition bằng cách sử dụng tính năng so sánh nhanh các thực thểO(1)(===) khi tham chiếu tập hợp không thay đổi. Tránh chuyển đổi các tập hợp lớn thành Tập hợp bất biến Kotlinx hoặc chú thích các lớp chứa tập hợp bằng@Immutablehoặc@Stable, trừ phi bạn đặc biệt yêu cầu tính bằng cấu trúc (O(N).equals()), vì việc so sánh mọi phần tử trên mỗi lần kết hợp lại có thể tốn kém hơn so với chính việc kết hợp lại. - Các mô-đun khác: Compose coi các lớp trong những mô-đun mà trình biên dịch Compose không chạy là không ổn định (được so sánh bằng
===trong chế độ Bỏ qua mạnh). Nếu một nguồn dữ liệu thường xuyên tạo lại các mô hình nhỏ, đơn giản từ các mô-đun không phải Compose có các giá trị giống hệt nhau, bạn có thể định cấu hình tệp cấu hình độ ổn định hoặc sử dụng@Stablehoặc@Immutabletrong đó.equals()có chi phí thấp.
Tài liệu đọc thêm
- Hiệu suất: Để biết thêm các mẹo gỡ lỗi về hiệu suất của Compose, hãy xem hướng dẫn về các phương pháp hay nhất và bài nói tại I/O của chúng tôi.