Chọn thư viện một cách khôn ngoan

Để bật tính năng tối ưu hoá ứng dụng, bạn phải sử dụng các thư viện tương thích với tính năng tối ưu hoá Android. Nếu một thư viện không được định cấu hình để tối ưu hoá cho Android (ví dụ: nếu thư viện đó sử dụng phản chiếu mà không đi kèm các quy tắc giữ liên kết), thì thư viện đó có thể không phù hợp với ứng dụng Android. Trang này giải thích lý do một số thư viện phù hợp hơn để tối ưu hoá ứng dụng và cung cấp các mẹo chung giúp bạn lựa chọn.

Ưu tiên codegen hơn reflection

Nhìn chung, bạn nên chọn các thư viện sử dụng tạo mã (codegen) thay vì phản chiếu. Với codegen, trình tối ưu hoá có thể dễ dàng xác định mã nào thực sự được dùng trong thời gian chạy và mã nào có thể bị xoá. Có thể khó biết liệu một thư viện có sử dụng codegen hay reflection hay không, nhưng có một số dấu hiệu – hãy xem các mẹo để được trợ giúp.

Để biết thêm thông tin về codegen so với reflection, hãy xem bài viết Tối ưu hoá cho tác giả thư viện.

Mẹo chung khi chọn thư viện

Hãy sử dụng những mẹo này để đảm bảo các thư viện của bạn tương thích với tính năng tối ưu hoá ứng dụng.

Kiểm tra các vấn đề về việc tối ưu hoá

Khi cân nhắc một thư viện mới, hãy xem xét trình theo dõi vấn đề và các cuộc thảo luận trực tuyến của thư viện để kiểm tra xem có vấn đề nào liên quan đến việc giảm thiểu hoặc định cấu hình tính năng tối ưu hoá ứng dụng hay không. Nếu có, bạn nên cố gắng tìm các lựa chọn thay thế cho thư viện đó. Lưu ý những điều sau:

  • Các thư viện AndroidX và các thư viện như Hilt hoạt động hiệu quả với việc tối ưu hoá ứng dụng vì chúng sử dụng codegen thay vì phản chiếu. Khi sử dụng tính năng phản chiếu, họ cung cấp các quy tắc lưu giữ tối thiểu để chỉ giữ lại mã cần thiết.
  • Các thư viện chuyển đổi tuần tự thường dùng tính năng phản chiếu để tránh mã nguyên mẫu khi khởi tạo hoặc chuyển đổi tuần tự các đối tượng. Thay vì các phương pháp dựa trên phản chiếu (chẳng hạn như Gson cho JSON), hãy tìm các thư viện sử dụng codegen để tránh những vấn đề này, ví dụ: bằng cách sử dụng Kotlin Serialization thay thế.
  • Bạn nên tránh dùng các thư viện có chứa quy tắc giữ lại trên toàn gói nếu có thể. Các quy tắc giữ lại trên toàn gói có thể giúp giải quyết lỗi, nhưng các quy tắc giữ lại trên diện rộng cuối cùng sẽ phải được tinh chỉnh để chỉ giữ lại mã cần thiết. Để biết thêm thông tin, hãy xem bài viết Từng bước áp dụng các hoạt động tối ưu hoá.
  • Các thư viện không được yêu cầu bạn sao chép và dán quy tắc lưu giữ từ tài liệu vào một tệp trong dự án của bạn, đặc biệt là các quy tắc lưu giữ trên toàn gói. Về lâu dài, những quy tắc này sẽ trở thành gánh nặng bảo trì đối với nhà phát triển ứng dụng, đồng thời khó tối ưu hoá và thay đổi theo thời gian.

Bật tính năng tối ưu hoá sau khi thêm một thư viện mới

Khi bạn thêm một thư viện mới, hãy bật tính năng tối ưu hoá sau đó và kiểm tra xem có lỗi hay không. Nếu có lỗi, hãy tìm các lựa chọn thay thế cho thư viện đó hoặc viết các quy tắc giữ lại. Nếu một thư viện không tương thích với tính năng tối ưu hoá, hãy báo cáo lỗi cho thư viện đó.

Các quy tắc mang tính bổ sung

Xin lưu ý rằng các quy tắc giữ lại mang tính bổ sung. Điều này có nghĩa là một số quy tắc mà phần phụ thuộc thư viện bao gồm không thể bị xoá và có thể ảnh hưởng đến quá trình biên dịch các phần khác của ứng dụng. Ví dụ: nếu một thư viện có quy tắc vô hiệu hoá các hoạt động tối ưu hoá mã, thì quy tắc đó sẽ vô hiệu hoá các hoạt động tối ưu hoá cho toàn bộ dự án của bạn.

Kiểm tra việc sử dụng hiệu ứng phản chiếu (nâng cao)

Bạn có thể biết liệu một thư viện có sử dụng chế độ phản chiếu hay không bằng cách kiểm tra mã của thư viện đó. Nếu thư viện sử dụng chế độ phản chiếu, hãy kiểm tra để đảm bảo thư viện cung cấp các quy tắc giữ lại được liên kết. Có thể một thư viện đang sử dụng tính năng phản chiếu nếu thư viện đó làm những việc sau:

  • Sử dụng các lớp hoặc phương thức từ gói kotlin.reflect hoặc java.lang.reflect
  • Sử dụng hàm Class.forName hoặc classLoader.getClass
  • Đọc chú giải trong thời gian chạy, ví dụ: nếu chú giải lưu trữ một giá trị chú giải bằng cách sử dụng val value = myClass.getAnnotation() hoặc val value = myMethod.getAnnotation() rồi thực hiện một thao tác nào đó với value
  • Gọi các phương thức bằng tên phương thức dưới dạng một chuỗi, ví dụ:

    // Calls the private `processData` API with reflection
    myObject.javaClass.getMethod("processData", DataType::class.java)
    ?.invoke(myObject, data)
    

Lọc ra các quy tắc giữ lại không hợp lệ (nâng cao)

Bạn nên tránh các thư viện có quy tắc giữ lại mã mà bạn thực sự nên xoá. Nhưng nếu phải sử dụng, bạn có thể lọc các quy tắc như minh hoạ trong mã sau:

// If you're using AGP 8.4 and higher
buildTypes {
    release {
        optimization.keepRules {
          it.ignoreFrom("com.somelibrary:somelibrary")
        }
    }
}

// If you're using AGP 7.3-8.3
buildTypes {
    release {
        optimization.keepRules {
          it.ignoreExternalDependencies("com.somelibrary:somelibrary")
        }
    }
}

Nghiên cứu điển hình: Tại sao Gson bị gián đoạn khi tối ưu hoá

Gson là một thư viện chuyển đổi tuần tự thường gây ra vấn đề về việc tối ưu hoá ứng dụng vì thư viện này sử dụng nhiều chức năng phản chiếu. Đoạn mã sau đây cho thấy cách Gson thường được dùng, có thể dễ dàng gây ra sự cố trong thời gian chạy. Lưu ý rằng khi dùng Gson để lấy danh sách các đối tượng Người dùng, bạn không gọi hàm tạo hoặc truyền một nhà máy đến hàm fromJson(). Việc tạo hoặc sử dụng các lớp do ứng dụng xác định mà không có một trong hai lớp sau đây là dấu hiệu cho thấy một thư viện có thể đang sử dụng tính năng phản chiếu không giới hạn:

  • Lớp ứng dụng triển khai một thư viện, hoặc giao diện hoặc lớp tiêu chuẩn
  • Trình bổ trợ tạo mã như KSP
class User(val name: String)
class UserList(val users: List<User>)

// This code runs in debug mode, but crashes when optimizations are enabled
Gson().fromJson("""[{"name":"myname"}]""", User::class.java).toString()

Khi phân tích mã này và không thấy UserList hoặc User được khởi tạo ở bất kỳ đâu, R8 có thể đổi tên các trường hoặc xoá những hàm khởi tạo có vẻ không được dùng, khiến ứng dụng của bạn gặp sự cố. Nếu đang sử dụng bất kỳ thư viện nào khác theo cách tương tự, bạn nên kiểm tra để đảm bảo rằng các thư viện đó sẽ không ảnh hưởng đến việc tối ưu hoá ứng dụng. Nếu có, hãy tránh sử dụng các thư viện đó.

Xin lưu ý rằng cả RoomHilt đều tạo các loại do ứng dụng xác định, nhưng sử dụng codegen để tránh nhu cầu phản ánh.