我有一个应用程序从相机预览中获取固定数量的图像,并将它们转换为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
已发布的here,但没有运气......
我为什么会遇到这个OOM错误?
答案 0 :(得分:2)
Android中的内存非常有限,这就是您获得此异常的原因。一般来说,你不应该在内存中存储这么多图像,只应在需要时加载它们(即显示它们或用它们做某事)并且应该尽快处理它们(recycle()
)因为你已经完成了它们。此外,您只应以尽可能低的分辨率加载它们。
说完所有这些,并且不知道为什么你必须将它们都放在内存中(你可能有正当理由),你可以通过在清单中指定适当的属性来增加应用程序的堆大小({{ 3}})但即使这并不能保证你可以加载太多图像。
请记住,默认情况下,Android会为您的图像使用每像素4个字节,因此如果您有30张图像,每张图像的像素密度为100万,那么您将使用1.2亿字节或大约120MB的内存。相比之下,应用程序的默认分配字节可以低至16mb(取决于许多情况。请参阅此处了解更多详细信息:http://developer.android.com/guide/topics/manifest/application-element.html#largeHeap)。
如果您可以以某种方式更改代码,以便不必将它们全部加载到内存中,您可以查看位图缓存(Android heap size on different phones/devices and OS versions),这可以极大地帮助您的内存管理问题。
答案 1 :(得分:1)
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。不要&#34;存储&#34;单个或其他任何地方的Bitmap
对象。这将始终导致OutOfMemoryError
。每次要使用时都重新创建Bitmap
。
修改强>
另请参阅官方ThreadSample示例和Displaying Bitmaps Efficiently教程。