【问题标题】:Out of memory Exception when creating bitmap for 2nd time第二次创建位图时出现内存不足异常
【发布时间】:2013-11-14 22:22:03
【问题描述】:

在我的 android 应用程序中,我需要拍照。第一张照片很好,上传到服务器,因此可以通过电子邮件发送给用户。这工作正常。然而,当我想上传第二张图片时,它会显示内存不足异常。我不知道为什么,但不知何故。

我的 logcat 输出可以在这个 pastebin 链接找到:http://pastebin.com/uVduy3d9

我处理图片的代码如下:

首先检查手机是否有摄像头:

Camera cam = Camera.open();
    if (cam != null) {
        if (savedInstanceState != null
                && savedInstanceState.getBoolean("Layout")) {
            setContentView(R.layout.registration_edit);
            initializeAccountDetails((User) savedInstanceState
                    .getSerializable(EXTRA_MESSAGE));
            inAccountDetails = true;
        } else {
            setContentView(R.layout.step_4);
            ((Button) findViewById(R.id.snap)).setOnClickListener(this);
            ((Button) findViewById(R.id.rotate)).setOnClickListener(this);
            cam.stopPreview();
            cam.release();
            cam = null;
        }
    } else {
        if (savedInstanceState != null
                && savedInstanceState.getBoolean("Layout")) {
            setContentView(R.layout.registration_edit);
            initializeAccountDetails((User) savedInstanceState
                    .getSerializable(EXTRA_MESSAGE));
            inAccountDetails = true;
        } else {
            setContentView(R.layout.step_4b);
        }
    }

当点击按钮 Snap 时,会触发以下 onClick 事件:

@Override
public void onClick(View v) {
    if (v.getId() == R.id.snap) {
        File directory = new File(Environment.getExternalStorageDirectory()
                + "/BandenAnalyse/Images/");
        if (directory.exists()) {
            Intent i = new Intent("android.media.action.IMAGE_CAPTURE");
            File f = new File(Environment.getExternalStorageDirectory(),
                    "/BandenAnalyse/Images/IMG_" + _timeStamp + ".jpg");
            _mUri = Uri.fromFile(f);
            i.putExtra(MediaStore.EXTRA_OUTPUT, _mUri);
            startActivityForResult(i, TAKE_PICTURE);
        } else {
            directory.mkdir();
            this.onClick(v);
        }
    } else {
        if (_mPhoto != null) {
            Matrix matrix = new Matrix();
            matrix.postRotate(90);
            _mPhoto = Bitmap.createBitmap(_mPhoto, 0, 0,
                    _mPhoto.getWidth(), _mPhoto.getHeight(), matrix, true);
            ((ImageView) findViewById(R.id.photo_holder))
                    .setImageBitmap(_mPhoto);
_mPhoto.recycle();
        }
    }
}

当照片被拍摄时,结果方法将被触发:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    switch (requestCode) {
    case TAKE_PICTURE:
        if (resultCode == Activity.RESULT_OK) {
            getContentResolver().notifyChange(_mUri, null);
            ContentResolver cr = getContentResolver();
            try {
                _mPhoto = android.provider.MediaStore.Images.Media
                        .getBitmap(cr, _mUri);

                Display display = getWindowManager().getDefaultDisplay();
                Point size = new Point();
                display.getSize(size);
                int width = size.x;
                int scale = _mPhoto.getWidth() / width;
                BitmapFactory.Options o = new BitmapFactory.Options();
                o.inSampleSize = 8;
                Debug.out(PATH_TO_PHOTO);
                Bitmap temp = BitmapFactory.decodeFile(PATH_TO_PHOTO, o);

                _mPhoto = Bitmap.createScaledBitmap(
                                            temp,
                                            _mPhoto.getWidth() / scale, _mPhoto.getHeight()
                                                    / scale, false);

                temp.recycle();
                ((ImageView) findViewById(R.id.photo_holder))
                        .setImageBitmap(_mPhoto);
            } catch (Exception e) {
                Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT)
                        .show();
            }
        }
    }
}

错误应该出现在最后一种方法中,因为当我处于相机模式并想要返回我的应用程序时会发生错误。 如何修复此错误?我错过了什么吗?

编辑:

在函数中添加代码:OnActivityResult。 如解决方案之一所述,创建了一个临时对象。太糟糕了,这无助于解决错误。

错误Out of memory Exception发生在以下行:

_mPhoto = android.provider.MediaStore.Images.Media.getBitmap(cr, _mUri);

【问题讨论】:

  • 我认为您的图像没有被压缩。因为在 logcat 的第一行,它指定了 i/p 和 o/p,宽度和高度是相同的。
  • 图片未压缩,但我不希望它被压缩导致质量损失?
  • 您想将图像发送到服务器。而且您还将其设置为 imageview。尝试评论该代码(设置为 imageview)并检查它是否有效。
  • 我为什么要这样做?然后图像将不再显示在活动中。但仍然出现错误。

标签: java android exception bitmap out-of-memory


【解决方案1】:

您不应该创建位图并在没有保留参考的情况下使用它,因为您必须释放它以进行良好的内存管理。

你做了什么:

_mPhoto = Bitmap.createScaledBitmap(
                        BitmapFactory.decodeFile(PATH_TO_PHOTO, o),
                        _mPhoto.getWidth() / scale, _mPhoto.getHeight()
                                / scale, false);

不好! ;)

喜欢:

Bitmap temp = BitmapFactory.decodeFile(PATH_TO_PHOTO, o);

_mPhoto = Bitmap.createScaledBitmap(
                            temp,
                            _mPhoto.getWidth() / scale, _mPhoto.getHeight()
                                    / scale, false);

temp.recycle(); //this call is the key ;) 

请记住:“创建的每个位图都必须回收,否则它会在某些时候因 OOM 错误而崩溃”。

希望有帮助!

您应该阅读更多关于 android Bitmaps and memory management 的信息以获得完整的理解;)

【讨论】:

  • 我按照你说的做了,但错误仍然存​​在,我将用编辑的部分更新问题:)
  • 问题已更新为您的代码。你对思维的看法是对的。然而不知何故,这个错误并没有解决:(
  • 那么你的位图可能太大了。尝试获得首选尺寸。请参阅 developer.android.com/training/displaying-bitmaps/… 处的 calculateInSampleSize 方法
  • 如果我的位图太大,它应该在第一次尝试创建位图时就失败了,对吧?然而实际上错误发生在第二次。出错后它带我去上一个活动,然后当我再次去拍照活动并拍照时,一切都很好
  • 当我不压缩我的位图时,上传时间会变长一点。当我压缩上传时间变得更少
猜你喜欢
  • 2011-08-07
  • 1970-01-01
  • 2014-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-24
  • 1970-01-01
相关资源
最近更新 更多