【问题标题】:App crashes after taking multiple pictures from Android camera从 Android 相机拍摄多张照片后应用程序崩溃
【发布时间】:2013-02-28 13:17:27
【问题描述】:

我正在为 Android 开发一个应用程序,该应用程序应该从相机拍摄照片并将这些图像用作应用程序的个人资料图片。但是,该应用程序在前 3-4 张照片上运行良好,但是当我尝试拍摄更多照片时,该应用程序崩溃了。原因是内存泄漏。

这是相机启动意图的代码:

String fileName = "temp.jpg";
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, fileName);
mCapturedImageURI = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
takePictureIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mCapturedImageURI);
startActivityForResult(takePictureIntent,RESULT_LOAD_IMAGE_CAMERA);

这是接收意图的代码:

if (requestCode == RESULT_LOAD_IMAGE_CAMERA && resultCode == RESULT_OK ) {
    String[] projection = { MediaStore.Images.Media.DATA};
    Cursor cursor = managedQuery(mCapturedImageURI, projection, null, null, null);
    final int column_index_data = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
    cursor.moveToFirst();
    String capturedImageFilePath = cursor.getString(column_index_data);
    profilePic.setImageURI(Uri.fromFile(new  File(capturedImageFilePath)));
}

这是日志:

02-28 18:28:36.727: E/dalvikvm-heap(4081): 9830400-byte external allocation too large for this process.
02-28 18:28:36.727: E/GraphicsJNI(4081): VM won't let us allocate 9830400 bytes
02-28 18:28:36.824: E/AndroidRuntime(4081): FATAL EXCEPTION: main
02-28 18:28:36.824: E/AndroidRuntime(4081): java.lang.OutOfMemoryError: bitmap size    exceeds VM budget
02-28 18:28:36.824: E/AndroidRuntime(4081):     at   android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at   android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:562)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at  android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:426)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.graphics.drawable.Drawable.createFromStream(Drawable.java:657)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.widget.ImageView.resolveUri(ImageView.java:509)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.widget.ImageView.setImageURI(ImageView.java:293)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at com.octanetech.cortes.ProfileActivity.onActivityResult(ProfileActivity.java:596)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.app.Activity.dispatchActivityResult(Activity.java:3890)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.app.ActivityThread.deliverResults(ActivityThread.java:3511)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.app.ActivityThread.handleSendResult(ActivityThread.java:3557)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.app.ActivityThread.access$2800(ActivityThread.java:125)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2063)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.os.Handler.dispatchMessage(Handler.java:99)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.os.Looper.loop(Looper.java:123)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.app.ActivityThread.main(ActivityThread.java:4627)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at java.lang.reflect.Method.invokeNative(Native Method)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at java.lang.reflect.Method.invoke(Method.java:521)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:871)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at dalvik.system.NativeStart.main(Native Method)

我们将不胜感激。

【问题讨论】:

标签: android android-camera


【解决方案1】:

替换这一行

profilePic.setImageURI(Uri.fromFile(new  File(capturedImageFilePath)));

您是直接从 sdcard 加载图像,可能会导致内存问题。

试试这个

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize=8;      // 1/8 of original image
Bitmap b = BitmapFactory.decodeFile(capturedImageFilePath,options);
profilePic.setImageBitmap(b);

【讨论】:

  • 感谢您的回复。我不太关心内存的大小,我更担心的是内存泄漏正在发生。不知何故,相机捕获的图像在垃圾收集中没有被删除。它被存储在应用程序的内存中。我们可以采用这种方法,但它只会将我的应用程序崩溃延迟 8 倍,并不能完全阻止它。
【解决方案2】:

最后我自己解决了这个问题。导致内存泄漏的主要问题是我没有回收位图对象。我只是用另一个位图图像替换位图对象。以为对象被另一个位图图像替换了,但之前的位图图像仍然存在于内存中。因此,在从相机拍摄多张图像时,位图图像堆积起来并引发了内存不足的异常。

因此,在将新图像分配给 Bitmap 对象之前,我玩了一个技巧来回收(删除)Bitmap 图像。 我刚用过

mImageBitmap.recycle();

这会清除之前的位图图像,并且没有发生内存泄漏。希望它也对其他人有所帮助。

【讨论】:

    【解决方案3】:

    尝试使用 inSampleSize 缩放较大的位图,如下所示: 摘自@Fedor 的惰性列表 https://github.com/thest1/LazyList/blob/master/src/com/fedorvlasov/lazylist/ImageLoader.java

    public int inSampleSize

    如果设置为大于 1 的值,则请求解码器对原始图像进行二次采样,返回较小的图像以节省内存。

    //decodes image and scales it to reduce memory consumption
        private Bitmap decodeFile(File f){
            try {
                //decode image size
                BitmapFactory.Options o = new BitmapFactory.Options();
                o.inJustDecodeBounds = true;
                FileInputStream stream1=new FileInputStream(f);
                BitmapFactory.decodeStream(stream1,null,o);
                stream1.close();
    
                //Find the correct scale value. It should be the power of 2.
                final int REQUIRED_SIZE=70;
                int width_tmp=o.outWidth, height_tmp=o.outHeight;
                int scale=1;
                while(true){
                    if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
                        break;
                    width_tmp/=2;
                    height_tmp/=2;
                    scale*=2;
                }
    
                //decode with inSampleSize
                BitmapFactory.Options o2 = new BitmapFactory.Options();
                o2.inSampleSize=scale;
                FileInputStream stream2=new FileInputStream(f);
                Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, o2);
                stream2.close();
                return bitmap;
            } catch (FileNotFoundException e) {
            } 
            catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    

    希望对您有所帮助:

    【讨论】:

    • 感谢您的回复。我不太关心内存的大小,我更担心的是内存泄漏正在发生。不知何故,相机捕获的图像在垃圾收集中没有被删除。它被存储在应用程序的内存中。我们可以采用这种方法,但它只会延迟我的应用程序崩溃并不能完全阻止它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多