Tối ưu hoá hiệu suất cho hình ảnh

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. Bạn có thể dễ dàng gặp phải OutOfMemoryError khi làm việc với các bitmap lớn. 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.

Chỉ tải kích thước bitmap bạn cần

Hầu hết các điện thoại thông minh đều có máy ảnh với độ phân giải cao tạo ra tệp hình ảnh lớn. Nếu đang hiển thị hình ảnh trên màn hình, bạn phải giảm độ phân giải của hình ảnh hoặc chỉ tải lên hình ảnh có kích thước tối đa bằng kích thước của vùng chứa hình ảnh. Việc tải liên tục các hình ảnh lớn hơn mức cần thiết có thể sử dụng hết bộ nhớ đệm GPU. Điều này dẫn đến việc hiển thị giao diện người dùng kém hiệu quả hơn.

Cách quản lý kích thước hình ảnh:

  • Giảm kích thước tệp hình ảnh càng nhỏ càng tốt (mà không ảnh hưởng đến hình ảnh đầu ra).
  • Hãy cân nhắc chuyển đổi hình ảnh của bạn sang định dạng WEBP thay vì định dạng JPEG hoặc PNG.
  • Cung cấp hình ảnh nhỏ hơn cho nhiều độ phân giải màn hình (xem Mẹo #3).
  • Sử dụng thư viện tải hình ảnh. Thư viện này sẽ giảm kích thước hình ảnh theo tỷ lệ để vừa với kích thước của chế độ xem trên màn hình. Điều này có thể giúp cải thiện hiệu suất tải của màn hình.

Sử dụng vectơ trên bitmap nếu có thể

Khi trình bày nội dung nào đó trên màn hình, bạn cần quyết định xem nội dung đó có thể được biểu thị dưới dạng vectơ hay không. Hãy ưu tiên hình ảnh vectơ hơn so với bitmap, vì các hình ảnh này không tạo pixel khi bạn điều chỉnh hình ảnh theo tỷ lệ sang các kích thước khác nhau. Tuy nhiên, không phải mọi thứ đều có thể được biểu thị dưới dạng vectơ – bạn không thể chuyển đổi hình ảnh được chụp bằng máy ảnh thành vectơ.

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ế.

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 trong việc xử lý hình ảnh (ví dụ: viết một hàm bằng cho Bitmaps sẽ tốn nhiều tài nguyên điện toán), Painter API rõ ràng không được đánh dấu là lớp Stable (Ổn định). 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 có thể vẽ dưới dạng tham số cho thành phần kết hợp, 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) {

}

Không lưu trữ bitmap trong bộ nhớ lâu hơn mức cần thiết

Bạn tải càng nhiều bitmap vào bộ nhớ, thì bạn càng có nhiều khả năng sẽ hết bộ nhớ trên thiết bị. Ví dụ: nếu tải một danh sách lớn các thành phần kết hợp Image trên màn hình, hãy sử dụng LazyColumn hoặc LazyRow để đảm bảo rằng bộ nhớ được giải phóng khi cuộn một danh sách dài.

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.