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á Android (ví dụ: nếu thư viện sử dụng tính năng phản chiếu mà không đóng gói các quy tắc giữ lại liên quan), 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à đưa ra các mẹo chung để giúp bạn lựa chọn.

Ưu tiên codegen hơn phản chiếu

Nhìn chung, bạn nên chọn các thư viện sử dụng tính năng tạo mã (codegen) thay vì tính năng 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 sử dụng trong thời gian chạy và mã nào có thể bị xoá. Có thể khó xác định xem một thư viện có sử dụng codegen hay phản chiếu hay không, nhưng có một số dấu hiệu – hãy xem mẹo để được trợ giúp.

Để biết thêm thông tin về codegen so với phản chiếu, hãy xem phần 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 các mẹo sau để đảm bảo 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ề tối ưu hoá

Khi cân nhắc một thư viện mới, hãy xem trình theo dõi lỗi 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 rút gọn 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 tìm các thư viện thay thế cho thư viện đó. Hãy lưu ý những điều sau:

  • Thư viện AndroidX và các thư viện như Hilt hoạt động hiệu quả với tính năng tối ưu hoá ứng dụng vì các thư viện này sử dụng codegen thay vì phản chiếu. Khi sử dụng tính năng phản chiếu, các công cụ này sẽ cung cấp các quy tắc giữ lại tối thiểu để chỉ giữ lại mã cần thiết.
  • Thư viện chuyển đổi tuần tự thường sử dụng tính năng phản chiếu để tránh mã nguyên mẫu khi tạo bản sao 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, chẳng hạn như bằng cách sử dụng Kotlin Serialization.
  • Bạn nên tránh sử dụng các thư viện có 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 cuối cùng, bạn nên tinh chỉnh các quy tắc giữ lại rộng để chỉ giữ lại mã cần thiết. Để biết thêm thông tin, hãy xem phần Từng bước áp dụng các biện pháp tối ưu hoá.

Bật tính năng tối ưu hoá sau khi thêm 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 nào không. Nếu có lỗi, hãy tìm các giải pháp thay thế cho thư viện đó hoặc viết 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 gửi lỗi liên quan đến thư viện đó.

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

Xin lưu ý rằng các quy tắc giữ nguyên sẽ được cộng dồn. Điều này có nghĩa là bạn không thể xoá một số quy tắc nhất định mà phần phụ thuộc thư viện bao gồm và các quy tắc đó 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 bao gồm một quy tắc để tắt tính năng tối ưu hoá mã, thì quy tắc đó sẽ tắt tính năng tối ưu hoá cho toàn bộ dự án.

Kiểm tra việc sử dụng tính năng phản chiếu (nâng cao)

Bạn có thể biết được một thư viện có sử dụng tính năng 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 tính năng 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 liên quan. Thư viện có thể đang sử dụng tính năng phản chiếu nếu thư viện đó thực hiện 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 các 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ữ giá trị chú giải bằng val value = myClass.getAnnotation() hoặc val value = myMethod.getAnnotation(), sau đó thực hiện một thao tác nào đó với value
  • Gọi các phương thức bằng cách sử dụng tên phương thức dưới dạng 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ã cần xoá. Tuy nhiên, nếu phải sử dụng các quy tắc này, 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: Lý do Gson bị lỗi 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 tính năng phản chiếu. Đoạn mã sau đây cho thấy cách sử dụng Gson thường gặp, điều này có thể dễ dàng gây ra sự cố trong thời gian chạy. Lưu ý rằng khi sử dụng Gson để lấy danh sách đối tượng Người dùng, bạn không gọi hàm khởi 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 những điều sau đây là dấu hiệu cho thấy thư viện có thể đang sử dụng tính năng phản chiếu mở:

  • Lớp ứng dụng triển khai 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 R8 phân tích mã này và không thấy UserList hoặc User được tạo bản sao ở bất kỳ đâu, R8 có thể đổi tên các trường hoặc xoá các hàm khởi tạo có vẻ như không được sử 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 RoomHilt đều tạo các loại do ứng dụng xác định, nhưng sử dụng codegen để tránh cần phải phản chiếu.