2013-08-15 51 views
12

Tôi là người mới đối với tất cả chủ đề quản lý bộ nhớ, vì vậy có rất nhiều điều tôi không hiểu.
Tôi đang cố gắng để cache một hình ảnh trong ứng dụng của tôi, nhưng tôi đang gặp rắc rối với tiêu thụ bộ nhớ của nó:Android - Bộ nhớ cache bitmap chiếm rất nhiều bộ nhớ

Tất cả các mã Bitmap Chaching là khá nhiều sao chép dán từ đây: http://developer.android.com/training/displaying-bitmaps/index.html

tôi sửa lỗi mã và kiểm tra kích thước heap trong giao diện DDMS trong nhật thực, và có khoảng 15mb nhảy sau những dòng mã:

 options.inJustDecodeBounds = false; 
     return BitmapFactory.decodeResource(res, resId, options); 

trong phương pháp "decodeSampledBitmapFromResource".

Hình ảnh có kích thước 1024x800, 75kb tệp jpg. Theo những gì tôi đã thấy trên internet, dung lượng bộ nhớ mà hình ảnh này phải chụp là khoảng 1024 * 800 * 4 (Bytes trên mỗi pixel) = 3.125mb

Tất cả các chủ đề liên quan đến chủ đề này don ' t nói lý do tại sao nó lấy bộ nhớ nhiều hơn nó nên. Có cách nào để lưu trữ một hình ảnh với một lượng bộ nhớ hợp lý không?

EDIT

tôi đã cố gắng sử dụng phương pháp decodeFile gợi ý trên @ ArshadParwez của câu trả lời dưới đây. Sử dụng phương pháp này, sau khi phương thức BitmapFactory.decodeStream bộ nhớ được tăng lên chỉ 3,5MB - giải quyết vấn đề, loại, nhưng tôi muốn cache bitmap trực tiếp từ tài nguyên.

Tôi nhận thấy rằng trong phương thức decodeResource có 2 bộ nhớ "nhảy" - một trong khoảng 3,5mb - đó là hợp lý và một số lạ khác là 14mb. 14mb được sử dụng cho cái gì và tại sao điều này lại xảy ra?

+0

Làm cách nào để lưu bộ nhớ đệm vào hệ thống tệp thay vì bộ nhớ hoạt động? –

+0

@PaulNikonowicz ngay cả khi nó giải quyết được vấn đề, có thể giả định rằng bộ nhớ thứ cấp là flash hoặc loại tương tự, viết thường xuyên với nó sẽ làm giảm thời gian sống của nó, những gì không phải là trường hợp cho bộ nhớ chính. –

+0

4 byte dành cho ARGB4444. Bạn có chắc chắn nó không phải là argb8888? – gunar

Trả lời

8

hình ảnh cũng được thu nhỏ theo mật độ quá họ có thể sử dụng nhiều bộ nhớ.

Ví dụ: nếu tệp hình ảnh nằm trong thư mục drawable (mật độ mdpi) và bạn chạy trên thiết bị xhdpi, cả chiều rộng và chiều cao sẽ tăng gấp đôi. Có thể this link có thể giúp bạn hoặc this one.

Vì vậy, trong ví dụ của bạn các byte file ảnh sẽ thực hiện là:

(1024 * 2) * (800 * 2) * 4 = 13.107.200 byte.

Sẽ tồi tệ hơn nếu bạn chạy trên thiết bị xxhdpi (như thiết bị HTC và Galaxy S4).

Bạn có thể làm gì?Hoặc đặt tệp hình ảnh vào thư mục mật độ chính xác (drawable-xhdpi hoặc drawable-xxhdpi) hoặc đặt nó trong drawable-nodpi (hoặc trong thư mục nội dung) và hạ thấp hình ảnh theo nhu cầu của bạn.

BTW bạn không phải đặt options.inJustDecodeBounds = false vì đó là hành vi mặc định. Trong thực tế, bạn có thể thiết lập null cho các tùy chọn bitmap.

Giới thiệu về tỷ lệ thu nhỏ, bạn có thể sử dụng google's way hoặc my way đều có những ưu điểm và nhược điểm riêng.

Giới thiệu về bộ nhớ đệm có nhiều cách để thực hiện. Phổ biến nhất là bộ nhớ cache LRU. Ngoài ra còn có một thay thế tôi đã tạo gần đây (liên kết here hoặc here) cho phép bạn lưu vào bộ nhớ cache nhiều hình ảnh hơn và tránh có OOM nhưng nó mang lại cho bạn rất nhiều trách nhiệm.

+1

ok. Tôi đã quên một mẹo khác về bitmap: bạn có thể đặt định dạng của chúng, vì vậy nếu bạn không cần độ trong suốt và chất lượng không quan trọng nhiều, bạn có thể sử dụng RGB_565 (sử dụng 2 byte cho mỗi pixel) thay vì ARGB_8888 mặc định (sử dụng 4 số byte trên mỗi pixel). liên kết tại đây: http://developer.android.com/reference/android/graphics/Bitmap.Config.html. cũng có một số video liên quan đến bộ nhớ và bitmap, ngay cả trên các trang web google IO. tôi khuyên bạn nên xem chúng, ngay cả khi họ không nói về vấn đề của bạn. –

6

Bạn có thể sử dụng phương pháp này để vượt qua các hình ảnh và có được một bitmap ra khỏi nó:

public Bitmap decodeFile(File f) { 
    Bitmap b = null; 
    try { 
     // Decode image size 
     BitmapFactory.Options o = new BitmapFactory.Options(); 
     o.inJustDecodeBounds = true; 

     FileInputStream fis = new FileInputStream(f); 
     BitmapFactory.decodeStream(fis, null, o); 
     fis.close(); 
     int IMAGE_MAX_SIZE = 1000; 
     int scale = 1; 
     if (o.outHeight > IMAGE_MAX_SIZE || o.outWidth > IMAGE_MAX_SIZE) { 
      scale = (int) Math.pow(
        2, 
        (int) Math.round(Math.log(IMAGE_MAX_SIZE 
          /(double) Math.max(o.outHeight, o.outWidth)) 
          /Math.log(0.5))); 
     } 

     // Decode with inSampleSize 
     BitmapFactory.Options o2 = new BitmapFactory.Options(); 
     o2.inSampleSize = scale; 
     fis = new FileInputStream(f); 
     b = BitmapFactory.decodeStream(fis, null, o2); 
     fis.close(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    return b; 
} 
+0

Tôi cũng đã nhận được rất nhiều sự cố như OutOfMemoryError khi làm việc với Hình ảnh. Vì vậy, sau đó tôi đã thực hiện phương pháp này bằng cách sử dụng một số toán học và sau đó tôi có thể sử dụng ngay cả một kích thước 5mb của hình ảnh mà không có bất kỳ tai nạn. – Arshu

+0

Trước khi tôi thử điều này, tôi muốn hiểu lý do - bạn có nói rằng BitmapFactory.decodeStream giải mã tốt hơn BitmapFactory.decodeResource không? –

+0

Nó không phải là, tôi đã sử dụng decodeStream vì tôi đã lấy một tập tin hình ảnh như là đầu vào và sử dụng một FileInputStream và nếu nó đã được một tập tin tài nguyên sau đó tôi đã sử dụng decodeResource – Arshu

1

@Ori Wasserman: Theo yêu cầu của bạn tôi đã sử dụng một phương pháp để có được hình ảnh từ thư mục nguồn và rằng quá Tôi đã sử dụng hình ảnh 7 MB. Tôi đưa hình ảnh 7 MB trong "res-> drawable" thư mục và với đoạn mã sau nó đã không sụp đổ và hình ảnh được hiển thị trong ImageView:

Bitmap image = BitmapFactory.decodeResource(getResources(), R.drawable.image_7mb); 
loBitmap = Bitmap.createScaledBitmap(image, width_of_screen , height_of_screen, true); 
imageview.setImageBitmap(loBitmap); 
+0

thực sự nó sẽ sử dụng RAM nhiều hơn những gì bạn nói, chỉ trong một thời gian ngắn. lý do là bạn tạo cả bitmap gốc và bitmap nhỏ. bạn sẽ không nhận thấy nó vì hình ảnh lớn sẽ được xử lý trên GC tiếp theo. điểm mà bạn có cả hai là điểm quan trọng nhất. –

+0

Bạn đang tạo 2 bitmap để đạt được 1 mục tiêu duy nhất rất bực bội đối với bộ nhớ. Hãy thử sử dụng BitmapFactory.Option trong vấn đề này. – neferpitou

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