Chẩn đoán các vấn đề về độ ổn định

Nếu đang gặp vấn đề về hiệu suất do việc kết hợp lại quá mức hoặc không cần thiết, bạn nên gỡ lỗi để ổn định ứng dụng của mình. Hướng dẫn này đề ra một số phương pháp để thực hiện điều này.

Layout Inspector

Layout Inspector trong Android Studio cho phép bạn xem thành phần kết hợp nào đang được kết hợp lại trong ứng dụng của mình. Công cụ này cũng cho thấy số lần Compose đã kết hợp lại hoặc bỏ qua một thành phần.

Đếm số lần kết hợp lại và bỏ qua trong Layout Inspector

Báo cáo trình biên dịch Compose

Trình biên dịch Compose có thể đưa ra kết quả suy luận về độ ổn định của nó để bạn kiểm tra. Bằng cách sử dụng kết quả này, bạn có thể xác định thành phần kết hợp nào có thể bỏ qua và thành phần nào thì không. Các tiểu mục tiếp theo tóm tắt cách sử dụng các báo cáo này, nhưng để biết thêm thông tin, hãy xem tài liệu kỹ thuật.

Thiết lập

Tính năng báo cáo của trình biên dịch không được bật theo mặc định. Bạn có thể bật tính năng này bằng cờ của trình biên dịch. Các bước thiết lập chính xác còn tuỳ thuộc vào dự án của bạn. Nhưng đối với hầu hết dự án, bạn có thể dán đoạn mã sau vào tệp build.gradle trong thư mục gốc.

Groovy

subprojects {
  tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
        kotlinOptions {
            if (project.findProperty("composeCompilerReports") == "true") {
                freeCompilerArgs += [
                        "-P",
                        "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" +
                                project.buildDir.absolutePath + "/compose_compiler"
                ]
            }
            if (project.findProperty("composeCompilerMetrics") == "true") {
                freeCompilerArgs += [
                        "-P",
                        "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" +
                                project.buildDir.absolutePath + "/compose_compiler"
                ]
            }
        }
    }
}

Kotlin

subprojects {
    tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
        kotlinOptions {
            if (project.findProperty("composeCompilerReports") == "true") {
                freeCompilerArgs += listOf(
                    "-P",
                    "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=${project.buildDir.absolutePath}/compose_compiler"
                )
            }
            if (project.findProperty("composeCompilerMetrics") == "true") {
                freeCompilerArgs += listOf(
                    "-P",
                    "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=${project.buildDir.absolutePath}/compose_compiler"
                )
            }
        }
    }
}

Chạy tác vụ

Để gỡ lỗi về tính ổn định của các thành phần kết hợp, hãy chạy tác vụ như sau:

./gradlew assembleRelease -PcomposeCompilerReports=true

Kết quả ví dụ

Tác vụ này xuất ra 3 tệp. Sau đây là các ví dụ kết quả đầu ra từ JetSnack.

  • <modulename>-classes.txt: Một báo cáo về tính ổn định của các lớp trong mô-đun này. Mẫu.
  • <modulename>-composables.txt: Một báo cáo về khả năng khởi động lại và bỏ qua của các thành phần kết hợp trong mô-đun. Mẫu.
  • <modulename>-composables.csv: Một phiên bản CSV của báo cáo về thành phần kết hợp. Bạn có thể nhập báo cáo này vào bảng tính hoặc xử lý bằng tập lệnh. Mẫu

Báo cáo về thành phần kết hợp

Tệp composables.txt nêu chi tiết từng hàm có khả năng kết hợp cho mô-đun nhất định, bao gồm cả độ ổn định của các tham số của hàm đó và liệu hàm đó có thể khởi động lại hay có thể bỏ qua hay không. Sau đây là một ví dụ giả định từ JetSnack:

restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun SnackCollection(
  stable snackCollection: SnackCollection
  stable onSnackClick: Function1<Long, Unit>
  stable modifier: Modifier? = @static Companion
  stable index: Int = @static 0
  stable highlight: Boolean = @static true
)

Thành phần kết hợp SnackCollection này hoàn toàn có thể khởi động lại, bỏ qua và ổn định. Thành phần này thường được ưa chuộng hơn, mặc dù chắc chắn là không bắt buộc phải sử dụng.

Mặt khác, hãy xem một ví dụ nữa.

restartable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
  stable index: Int
  unstable snacks: List<Snack>
  stable onSnackClick: Function1<Long, Unit>
  stable modifier: Modifier? = @static Companion
)

Không thể bỏ qua thành phần kết hợp HighlightedSnacks. Compose sẽ không bao giờ bỏ qua thành phần này trong quá trình kết hợp lại. Điều này xảy ra ngay cả khi không có tham số nào của thành phần này thay đổi. Nguyên nhân là do tham số unstable, snacks.

Báo cáo về các lớp

Tệp classes.txt này chứa một báo cáo tương tự về các lớp trong mô-đun nhất định. Đoạn mã sau đây là kết quả đối với lớp Snack:

unstable class Snack {
  stable val id: Long
  stable val name: String
  stable val imageUrl: String
  stable val price: Long
  stable val tagline: String
  unstable val tags: Set<String>
  <runtime stability> = Unstable
}

Để tham khảo, sau đây là định nghĩa của Snack:

data class Snack(
    val id: Long,
    val name: String,
    val imageUrl: String,
    val price: Long,
    val tagline: String = "",
    val tags: Set<String> = emptySet()
)

Trình biên dịch Compose đã đánh dấu Snack là không ổn định. Nguyên nhân là do kiểu của tham số tagsSet<String>. Đây là một kiểu dữ liệu bất biến, vì không phải là MutableSet. Tuy nhiên, về bản chất thì các lớp tập hợp tiêu chuẩn như Set, ListMap đều là các giao diện. Như vậy, phương thức triển khai cơ bản có thể vẫn có khả năng biến đổi.

Ví dụ: bạn có thể viết val set: Set<String> = mutableSetOf("foo"). Biến này là hằng số và kiểu dữ liệu đã khai báo của nó là không biến đổi được, nhưng vẫn có thể biến đổi phương thức triển khai. Trình biên dịch Compose không thể chắc chắn về tính bất biến của lớp này vì nó chỉ nhìn thấy kiểu dữ liệu đã khai báo. Do đó công cụ này đánh dấu tags là không ổn định.