2012-09-29 29 views
24

Tôi sẽ rất biết ơn nếu ai đó có thể xác nhận rằng tôi đã giải quyết vấn đề dưới đây một cách chính xác hoặc nếu có giải pháp thay thế?Android Bitmap tải hết lỗi bộ nhớ Galaxy S3 WXGA

Tôi có một ứng dụng tải hình ảnh lớn (ví dụ: 800 * 1720 pixel) vào bộ nhớ và hiển thị hình ảnh đó trong chế độ xem cuộn. Hình ảnh là một kế hoạch sàn cho một bảo tàng và tôi muốn có một bản đồ đơn giản như trải nghiệm di chuyển và phóng to. Các hình ảnh được tải tốt trên các thiết bị cũ, nhưng gây ra một lỗi bộ nhớ trên Samsung Galaxy S3.

Nhìn vào các thông điệp LogCat nó bật ra rằng trong creaing bitmap 22MB đã được cấp phát cho bitmap thay vì 800 * 1720 * 4 = 5,5MB. Về cơ bản 4x bộ nhớ được phân bổ theo yêu cầu của các thiết bị khác và đẩy mức sử dụng bộ nhớ lên trên kích thước heap 50MB.

Giải pháp được đề xuất cho vấn đề này là sử dụng tùy chọn BitmapFactory.Options.inSampleSize để giảm độ phân giải của hình ảnh được tải và yêu cầu ít bộ nhớ hơn. Tuy nhiên, điều này làm giảm chất lượng của hình ảnh, và tôi thực sự muốn hiển thị nó ở kích thước đầy đủ ở chất lượng gốc khi hoạt động tốt trên các thiết bị cũ hơn.

Sau nhiều lần cào xước, tôi kết luận rằng vấn đề là mật độ pixel trên màn hình WXGA của S3 là 2.0 và do đó đối với mỗi pixel trong ảnh, bitmap thực sự phân bổ 4 pixel. Với một chút thử và sai tôi phát hiện ra tôi có thể ngăn chặn điều này xảy ra bằng cách thiết lập options.inScaled = false;

http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inScaled

Trên đường đi, tôi cũng nhận ra rằng tôi có thể cắt giảm sử dụng bộ nhớ của tôi trong nửa để 2.7MB bằng cách sử dụng một độ chính xác thấp độ sâu màu của 2 pixel thay vì 4 pixel bằng cách đặt options.inPreferredConfig = Bitmap.Config.RGB_565;. Đối với floorpans của tôi điều này đã không ảnh hưởng đến chất lượng hình ảnh có thể nhìn thấy.

Mã cuối cùng là như sau:

String uri = "drawable/floorplan"; 
int imageResource = getResources().getIdentifier(uri, null, getPackageName()); 
BitmapFactory.Options options = new BitmapFactory.Options(); 
options.inPreferredConfig = Bitmap.Config.RGB_565; 
options.inScaled = false; 
Bitmap bm = BitmapFactory.decodeResource(getResources(), imageResource, options); 
IVfloorplan.setImageBitmap(bm); 

Khi hiển thị bitmap này bạn cần phải mở rộng nó lại lên. Để làm việc ra các tỉ lệ bạn có thể có được mật độ điểm ảnh từ:

float density = getResources().getDisplayMetrics().density; 

tôi giảm sử dụng bộ nhớ cho bitmap từ 22MB đến 2.7MB, mà trong một đống 50MB rất có ý nghĩa.

+3

Phân tích tốt và cảm ơn bạn đã giải pháp. – Simon

+0

Tôi nghĩ, có thể là tốt để cung cấp liên kết tài liệu ở đây mô tả một phần giống như vậy liên quan đến inSampleSize: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html. Và http://www.curious-creature.org/2010/12/08/bitmap-quality-banding-and-dithering/ về chơi với định dạng màu bitmap và đạo cụ/khuyết điểm của nó. – sandrstar

+0

tuyệt vời. Tôi nghĩ rằng điều này sẽ giúp ngay cả đối với các thiết bị khác có kích thước heap thấp hơn. Nhưng bạn nên thêm câu trả lời thay vì trả lời câu hỏi của bạn, vì nó vi phạm các quy tắc SO và làm cho câu hỏi an toàn khỏi bị xóa. –

Trả lời

2

Màn hình của S3 có độ phân giải rất cao, vì vậy nó khá dễ hiểu. Ngoài ra, nếu hình ảnh nằm trong thư mục drawable, nó có thể được tự động nâng cấp. Có thể có cách để tắt nó đi. Ngay cả khi kích thước hình ảnh của bạn không có cơ hội, hệ điều hành phải phân bổ bộ đệm để chứa hình ảnh, cũng có thể là một bộ đệm để hiển thị nó trên màn hình.

Cách khác là sử dụng ốp lát, được sử dụng trong các trò chơi như trò chơi SNES. Đây cũng là cách họ xử lý nhiều đồ họa mà không cần hết RAM. Bằng chứng cho thấy rằng đây là cách Google Maps có một bản đồ của Planet Earth. Bạn về cơ bản chop lên các hình ảnh lớn vào gạch và hiển thị các gạch trên màn hình như bạn đang panned cho họ (tất nhiên, có thể thêm 1 gạch trên mỗi bên).

Mặc dù đây là sau Honeycomb, nơi Google đặt mã để quản lý phân bổ Bitmap tốt hơn, hãy cẩn thận với phân bổ Bitmap. Nó giống như một chương trình C hơn là một chương trình Java, và đó là một ý tưởng tốt để quản lý nó như một chương trình. Nó rất dễ dàng để chạy ra khỏi không gian heap khi sử dụng các đối tượng Bitmap trong Android

Các vấn đề liên quan