Tối ưu hoá hình ảnh bitmap

Việc xử lý hình ảnh có thể nhanh chóng gây ra vấn đề về hiệu suất nếu bạn không cẩn thận. Ngay cả một hình ảnh đồ hoạ nhỏ ở định dạng nén như JPG hoặc PNG cũng có thể biến thành một bitmap lớn khi được giải mã để hiển thị.Nếu không sử dụng đồ hoạ một cách hiệu quả, bạn có thể gặp phải các vấn đề về bộ nhớ, ảnh hưởng đến hiệu suất của ứng dụng và các ứng dụng khác trên thiết bị. Hãy làm theo các phương pháp hay nhất này để đảm bảo ứng dụng của bạn hoạt động hiệu quả nhất.

Sử dụng thư viện tải hình ảnh

Bạn có thể cải thiện hiệu quả của ứng dụng bằng cách sử dụng các thư viện tải hình ảnh như Coil (cho các dự án ưu tiên Kotlin) hoặc Glide (cho các dự án Java). Các thư viện này giúp giảm mức sử dụng bộ nhớ của ứng dụng bằng cách thực hiện những việc như lưu hình ảnh vào bộ nhớ đệm, đổi kích thước hình ảnh đồ hoạ khi cần và tái sử dụng các đối tượng đồ hoạ.

Đổi kích thước hình ảnh khi thích hợp

Hãy nhớ sử dụng kích thước hình ảnh phù hợp với nhu cầu của bạn. Ví dụ: bạn không bao giờ được tải một hình ảnh lớn vào một hình thu nhỏ nhỏ. Thay vào đó, hãy sử dụng một phương thức như inSampleSize để tải phiên bản được lấy mẫu lại của hình ảnh.

Theo mặc định, các thư viện tải hình ảnh như Coil và Glide sẽ tự động xử lý việc lấy mẫu lại này cho bạn. Bạn có thể định cấu hình các chiến lược lấy mẫu xuống bằng cách sử dụng ImageLoader (cho Coil) hoặc DownsampleStrategy (cho Glide).

Cung cấp tài nguyên thay thế cho nhiều kích thước màn hình

Nếu bạn đang vận chuyển hình ảnh bằng ứng dụng, hãy cân nhắc cung cấp các thành phần có kích thước khác nhau cho các độ phân giải thiết bị khác nhau. Điều này có thể giúp giảm dung lượng tải xuống của ứng dụng trên các thiết bị và cải thiện hiệu suất vì ứng dụng này sẽ tải hình ảnh có độ phân giải thấp hơn trên thiết bị có độ phân giải thấp hơn. Để biết thêm thông tin về cách cung cấp bitmap thay thế cho các kích thước thiết bị khác nhau, hãy xem tài liệu bitmap thay thế.

Không áp dụng trực tiếp khoảng đệm

Đôi khi, bạn có thể cần thêm khoảng đệm vào hình ảnh. Ví dụ: bạn có thể muốn hình ảnh được bao quanh bởi một đường viền trong suốt để tạo hiệu ứng letterbox. Trong những trường hợp đó, không thêm trực tiếp khoảng đệm vào hình ảnh, thay đổi kích thước của hình ảnh. Thay vào đó, hãy giữ nguyên kích thước của hình ảnh, và điều chỉnh vị trí của hình ảnh trên màn hình bằng cách sử dụng InsetDrawable. Ngoài ra, bạn có thể thêm khoảng đệm vào Thành phần kết hợp hoặc Khung hiển thị chứa hình ảnh.

Chọn định dạng pixel phù hợp

Cân bằng bộ nhớ và chất lượng bằng cách chọn định dạng pixel phù hợp. Sử dụng RGB_565 khi bạn không cần độ trong suốt; định dạng này sử dụng một nửa bộ nhớ của định dạng ARGB_8888 mặc định.

Trong Glide, bạn có thể định cấu hình định dạng này bằng cách sử dụng DecodeFormat. Trong Coil, bạn có thể sử dụng thuộc tính bitmapConfig.

Sử dụng vectơ khi có thể

Đối với hình ảnh được tạo từ các hình dạng hình học, đồ họa vectơ nhỏ hơn nhiều so với bitmap và có thể điều chỉnh tỷ lệ một cách mượt mà cho mọi mật độ hiển thị. Khi thích hợp, hãy sử dụng các phần tử như ShapeDrawable để biểu thị hình ảnh đồ hoạ.

Giải phóng và tái sử dụng bitmap khi có thể

Các tệp đồ hoạ lớn có thể chiếm nhiều bộ nhớ. Để giảm tác động của các tệp này, bạn nên giải phóng hoặc tái sử dụng các đối tượng đồ hoạ bất cứ khi nào có thể.

Nếu bạn sử dụng thư viện tải hình ảnh, hãy nhớ giải phóng bitmap cho nhóm được quản lý của thư viện khi bạn không còn cần đến chúng nữa. Thư viện có thể tái sử dụng các đối tượng khi cần và duy trì bộ đệm bộ nhớ cho các nhu cầu trong tương lai.

Nếu bạn đang quản lý đồ hoạ theo cách thủ công, bạn nên giải phóng bitmap khi hoàn tất bằng cách gọi Bitmap.recycle và loại bỏ ngay tham chiếu Bitmap, thay vì dựa vào quá trình thu thập rác.

Các mẹo và thủ thuật khác

Phần này liệt kê một số cách khác để cải thiện hiệu suất của ứng dụng khi xử lý đồ hoạ.

Không đóng gói hình ảnh lớn bằng tệp AAB/APK

Một trong những nguyên nhân hàng đầu dẫn đến dung lượng tải xuống ứng dụng lớn là do đồ hoạ được đóng gói trong tệp AAB hoặc APK. Hãy sử dụng công cụ phân tích APK để đảm bảo rằng bạn không đóng gói tệp hình ảnh lớn hơn yêu cầu. Hãy giảm kích thước hoặc cân nhắc đặt hình ảnh trên máy chủ và chỉ tải hình ảnh xuống khi được yêu cầu.

Tìm bitmap dư thừa

Nếu bạn có nhiều bản sao của cùng một hình ảnh, điều đó sẽ lãng phí bộ nhớ. Bạn có thể sử dụng trình phân tích Android Studio để xác định hình ảnh đồ hoạ dư thừa. Sử dụng trình phân tích tệp báo lỗi để ghi tệp báo lỗi và lọc kết quả bằng cách chọn chế độ cài đặt duplicate bitmaps (bitmap trùng lặp).

Khi sử dụng ImageBitmap, hãy gọi prepareToDraw trước khi vẽ

Khi sử dụng ImageBitmap, để bắt đầu quá trình tải hoạ tiết lên GPU, hãy gọi ImageBitmap#prepareToDraw() trước khi thực sự vẽ hoạ tiết đó. Điều này giúp GPU chuẩn bị hoạ tiết và cải thiện hiệu suất hiển thị hình ảnh trên màn hình. Hầu hết các thư viện tải hình ảnh đều đã thực hiện việc tối ưu hoá này, nhưng nếu bạn đang tự làm việc với lớp ImageBitmap, thì đây là điều cần lưu ý.

Ưu tiên chuyển Int DrawableRes hoặc URL dưới dạng tham số vào thành phần kết hợp thay vì Painter

Do sự phức tạp của việc xử lý hình ảnh (ví dụ: việc viết một hàm bằng cho Bitmaps sẽ tốn nhiều tài nguyên tính toán), nên API Painter không được đánh dấu rõ ràng là ổn định bằng chú thích @Stable. Các lớp không ổn định có thể dẫn đến các bản tái cấu trúc không cần thiết vì trình biên dịch không thể dễ dàng dự đoán nếu dữ liệu thay đổi.

Do đó, bạn nên truyền URL hoặc mã tài nguyên drawable dưới dạng tham số cho composable, thay vì truyền Painter dưới dạng tham số.

// Prefer this:
@Composable
fun MyImage(url: String) {

}
// Over this:
@Composable
fun MyImage(painter: Painter) {

}