2013-04-29 27 views
6

Trong onPictureTaken, tôi muốn làm như sau:Làm cách nào để tránh "ngoại lệ bộ nhớ" khi thực hiện xử lý Bitmap?

Bitmap decodedPicture = BitmapFactory.decodeByteArray(data, 0, data.length); 
Matrix matrix = new Matrix(); 
matrix.preScale(-1.0f, 1.0f); 
Bitmap picture = Bitmap.createBitmap(decodedPicture, 0, 0, decodedPicture.getWidth(), decodedPicture.getHeight(), matrix, false); 

View v1 = mainLayout.getRootView(); 
v1.setDrawingCacheEnabled(true); 
Bitmap screenshot = Bitmap.createBitmap(v1.getDrawingCache()); 
v1.setDrawingCacheEnabled(false); 

Bitmap scaledPicture = Bitmap.createScaledBitmap(picture, screenshot.getWidth(), screenshot.getHeight(), true); 

Bitmap compos = Bitmap.createBitmap(scaledPicture.getWidth(), scaledPicture.getHeight(), Bitmap.Config.ARGB_8888); 

Canvas canvas = new Canvas(compos); 
canvas.drawBitmap(scaledPicture, new Matrix(), null); 
canvas.drawBitmap(screenshot, new Matrix(), null); 

MediaStore.Images.Media.insertImage(getContentResolver(), compos, "name" , "description"); 
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory()))); 

Yêu cầu duy nhất của tôi là tôi muốn lưu một bức ảnh chất lượng cao ... Có vẻ tôi có thể phải hy sinh đó.

Trên Nexus 4 và các thiết bị mới hơn, mã này chạy tốt và như mong đợi. Nhưng trên các thiết bị cũ có ít bộ nhớ hơn, tôi sắp hết RAM! :(

Làm cách nào để thực hiện thao tác xử lý ảnh tương tự mà không cần chạy lên giới hạn bộ nhớ? Tôi không cố gắng hiển thị những hình ảnh này trên màn hình, vì vậy các giải pháp phải làm với hình ảnh thu nhỏ lại 't thực sự áp dụng ở đây ...

+0

Bạn có thể vô giá trị một số tài liệu tham khảo, và sau đó gợi ý một GC? Điều đó sẽ loại bỏ một số dữ liệu không cần thiết ... – tilpner

Trả lời

3

bạn cần đọc bitmap với kích thước mẫu tăng lên, mẹo tìm kích thước mẫu chính xác sẽ không làm giảm độ phân giải khi bạn chia tỷ lệ hình ảnh. một mục blog về nó ở đây bao gồm một lớp tiện ích tốt đẹp để mở rộng quy mô,

http://zerocredibility.wordpress.com/2011/01/27/android-bitmap-scaling/

bạn có thể đơn giản hóa lớp học đó một chút tùy thuộc vào nhu cầu cụ thể của bạn.

jist là chỉ đọc kích thước của bitmap. tính toán kích thước mẫu tối ưu dựa trên kích thước được chia tỷ lệ mong muốn của bạn, đọc bitmap bằng cách sử dụng kích thước mẫu đó, sau đó cân chỉnh kích thước mẫu chính xác với kích thước bạn muốn.

0

Bạn có quá nhiều đối tượng Bitmap nằm xung quanh. thử tái chế/tái sử dụng một số điều này.

Không chắc chính xác yêu cầu của bạn là gì nhưng tôi có thể thấy bạn có thể tiết kiệm một số bộ nhớ bằng cách thực hiện thao tác này.

 Bitmap decodedPicture = BitmapFactory.decodeByteArray(data, 0, data.length); 
     Matrix matrix = new Matrix(); 
     matrix.preScale(-1.0f, 1.0f); 
     Bitmap picture = Bitmap.createBitmap(decodedPicture, 0, 0, decodedPicture.getWidth(), decodedPicture.getHeight(), matrix, false); 

     decodedPicture.recycle(); 
     decodedPicture=null; 

     View v1 = mainLayout.getRootView(); 
     v1.setDrawingCacheEnabled(true); 
     Bitmap screenshot = Bitmap.createBitmap(v1.getDrawingCache()); 
     v1.setDrawingCacheEnabled(false); 

     Bitmap scaledPicture = Bitmap.createScaledBitmap(picture, screenshot.getWidth(), screenshot.getHeight(), true); 

     picture.recycle(); 
     picture=null; 

     Bitmap compos = Bitmap.createBitmap(scaledPicture.getWidth(), scaledPicture.getHeight(), Bitmap.Config.ARGB_8888); 

     Canvas canvas = new Canvas(compos); 
     canvas.drawBitmap(scaledPicture, new Matrix(), null); 
     canvas.drawBitmap(screenshot, new Matrix(), null); 

     MediaStore.Images.Media.insertImage(getContentResolver(), compos, "name" , "description"); 
     sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory()))); 

Cũng nhìn vào bộ nhớ của bạn, hãy chắc chắn thiết bị bộ nhớ khôn ngoan bạn đang sử dụng là không quá lớn.

FYI, trên thiết bị honycomb hình ảnh bitmap pixel được phân bổ trên lớp gốc. Bạn cần recycle() hoặc finalizer() để khôi phục lại bộ nhớ

+0

sử dụng 'finalize()' là một ý tưởng tồi. http://stackoverflow.com/questions/2506488/java-finalize-method-call. Ngoài ra, từ tài liệu Android về 'recycle()': 'Đây là một cuộc gọi nâng cao, và thông thường không cần phải gọi, vì quá trình GC bình thường sẽ giải phóng bộ nhớ này khi không có thêm tham chiếu tới bitmap này.' –

0

Xét bạn không muốn thay đổi kích thước bitmap của bạn và không muốn hiển thị nó, tôi muốn làm một cái gì đó như thế này:

  1. Nạp Bitmap với inJustDecodeBounds để xem chiều cao ban đầu và chiều rộng của nó (mã từ here)

    final BitmapFactory.Options options = new BitmapFactory.Options(); 
    options.inJustDecodeBounds = true; 
    BitmapFactory.decodeResource(res, resId, options); 
    
    // Calculate inSampleSize 
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); 
    
  2. Tùy thuộc vào kích thước và bộ nhớ bạn có, bạn có thể trực tiếp xử lý nó từ đó (tức là nạp Bitmap) hoặc tiến hành để tải một số khối bitmap đã biết với phương thức Bitmap.createBitmap cho phép bạn chỉ tải một đoạn dữ liệu. Tùy chọn: xem xét chuyển đổi nó thành một mảng byte (xem mã bên dưới) và null + recycle() trước khi bạn xử lý đoạn.

đang

ByteArrayOutputStream byteArrayBitmapStream = new ByteArrayOutputStream(); 
bitmapPicture.compress(Bitmap.CompressFormat.PNG, COMPRESSION_QUALITY, byteArrayBitmapStream); 
byte[] b = byteArrayBitmapStream.toByteArray(); 
0

tôi sử dụng để làm việc với lớp Bitmap WeakReference và sau khi tôi luôn gọi rác trên WeakReference đối tượng dụ, đoạn mã cho hình ảnh xoay:

BitmapFactory.Options options = new BitmapFactory.Options(); 
options.inScaled = false; 
options.inPurgeable = true; 
options.inInputShareable = true; 
options.inPreferredConfig = Bitmap.Config.RGB_565; 
WeakReference<Bitmap> imageBitmapReference = new WeakReference<Bitmap>(BitmapFactory.decodeByteArray(params[0], 0, params[0].length, options)); 

Matrix mat = new Matrix(); 
mat.postRotate(90.0f); 
imageBitmapReference = new WeakReference<Bitmap (Bitmap.createBitmap(imageBitmapReference.get(), 0, 0, resolution[0], resolution[1], mat, true)); 

FileOutputStream fos = new FileOutputStream(filename); 
imageBitmapReference.get().compress(Bitmap.CompressFormat.PNG, 100, fos); 
fos.flush(); 
fos.close(); 
imageBitmapReference.get().recycle(); 

Và giải pháp thứ hai cách hoạt động với Bitmap và không nhận được Ngoại lệ OutOfMemory là sử dụng thư viện Universal Image Loader

(Tất nhiên là giải pháp thứ ba được đặt trong thuộc tính AndroidManifest của bạn android: largeHeap = "true" và thực sự KHÔNG SỬ DỤNG tài sản NÀY).

Vật liệu hoàn hảo là trên http://developer.android.com/training/displaying-bitmaps/index.html và video https://www.youtube.com/watch?v=_CruQY55HOk

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