我有一个应用程序,它从相机预览中获取固定数量的图像,并将它们转换为Bitmaps
列表。为此,我有以下代码:
private Camera.PreviewCallback SetPreviewCallBack() {
return new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
List<Bitmap> imageList = new ArrayList<Bitmap>();
for (int i=0; i<30; i++) // Let's suppose this is the real loop.
// It's not, as the real loop takes each camera preview frame,
// instead of inserting the same one 30 times.
// But for this example, it's OK
{
imageList.add(GetBitmap(
data,
previewWidth, // Calculated
previewHeight, // Calculated
previewFormat, // Calculated
previewRotation)); // Calculated
}
}
private Bitmap GetBitmap(byte[] data, int width, int height, int previewFormat, int rotation) {
YuvImage yuv = new YuvImage(data, previewFormat, width, height, null);
ByteArrayOutputStream out = new ByteArrayOutputStream();
yuv.compressToJpeg(new Rect(0, 0, width, height), 50, out);
byte[] bytes = out.toByteArray();
final Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
Bitmap imageResult = RotateImage(bitmap, 4 - rotation);
bitmap.recycle();
return imageResult;
}
private Bitmap RotateImage(Bitmap rotateImage, int rotation) {
Matrix matrix = new Matrix();
switch (rotation) {
case 1:
matrix.postRotate(270);
break;
case 2:
matrix.postRotate(180);
break;
case 3:
matrix.postRotate(90);
break;
}
return Bitmap.createBitmap(rotateImage, 0, 0, rotateImage.getWidth(),
rotateImage.getHeight(), matrix, true);
}
我所做的是:-我将此映像存储在Singleton
类上,以便从同一应用程序中包含的另一个Activity
访问它。-我再次调用这段代码(当某个事件发生时),并重复图像提取/保存过程。
03-05 09:35:13.339: E/AndroidRuntime(8762): FATAL EXCEPTION: Thread-818
03-05 09:35:13.339: E/AndroidRuntime(8762): java.lang.OutOfMemoryError
03-05 09:35:13.339: E/AndroidRuntime(8762): at android.graphics.Bitmap.nativeCreate(Native Method)
03-05 09:35:13.339: E/AndroidRuntime(8762): at android.graphics.Bitmap.createBitmap(Bitmap.java:726)
03-05 09:35:13.339: E/AndroidRuntime(8762): at android.graphics.Bitmap.createBitmap(Bitmap.java:703)
03-05 09:35:13.339: E/AndroidRuntime(8762): at android.graphics.Bitmap.createBitmap(Bitmap.java:636)
03-05 09:35:13.339: E/AndroidRuntime(8762): at com.facephi.sdk.ui.CameraPreview.RotateImage(CameraPreview.java:779)
03-05 09:35:13.339: E/AndroidRuntime(8762): at com.facephi.sdk.ui.CameraPreview.GetBitmap(CameraPreview.java:712)
我正试图使用最佳实践以正确的方式删除这里发布的未使用的Bitmaps
,但运气不好。。。
你知道我为什么会出现OOM错误吗?
您在Android中的内存非常有限,这就是为什么会出现此异常。一般来说,你不应该在内存中存储太多图像,只应该在需要时加载它们(即显示它们或对它们做一些事情),并且应该在处理完它们后立即处理它们(recycle()
)。此外,您应该只以尽可能低的分辨率加载它们。
说了所有这些,但不知道为什么必须将它们全部存储在内存中(你可能有正当的理由),你可以通过在清单中指定适当的属性来增加应用程序的堆大小(http://developer.android.com/guide/topics/manifest/application-element.html#largeHeap)但即便如此,也不能保证你能加载太多的图像。
请记住,默认情况下,Android将为您的图像使用每像素4字节,因此,如果您有30张图像,每张图像的像素密度为100万,则您将使用1.2亿字节或大约120MB的内存。相比之下,应用程序的默认分配字节可能低至微不足道的16mb(取决于许多情况。请参阅此处了解更多详细信息:不同手机/设备和操作系统版本上的Android堆大小)。
如果您可以以某种方式更改代码,使它们不必全部加载到内存中,那么您可以查看位图缓存(http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html)这可以极大地帮助您解决内存管理问题。
1.尝试使用
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize = 8;
options.inDither = false;
options.inPurgeable = true;
options.inInputShareable = true;
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
这将大大有助于节省内存。
2.不要将Bitmap
对象"存储"在singleton或其他任何地方。这将始终导致OutOfMemoryError
。每次你想使用Bitmap
时都要重新创建它。
编辑:
另请参阅官方的ThreadSample示例和高效显示位图教程。