如何克服此错误:java.lang.OutOfMemoryError:位图大小超过VM预算

时间:2011-09-30 06:48:49

标签: android

我正在尝试在Sqlite DB中添加图像并将图像从DB列出到listview ....我正在存储图像路径以获取图像。 当我在设备中列出来自DB的图像时,我收到类似java.lang.OutOfMemoryError: bitmap size exceeds VM budget

的错误

我每次都清除堆内存吗? 如何纠正这个..这是我的代码。

LView.class

mySQLiteAdapter = new SQLiteAdapter(this);
mySQLiteAdapter.openToWrite();                
mAlbum = (ImageView) findViewById(R.id.iv);
mAlbum.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Intent intent = new Intent(Intent.ACTION_PICK, 
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, IMG);
}
});

Button click = (Button) findViewById(R.id.button);
click.setOnClickListener(new OnClickListener() {
@Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        mySQLiteAdapter.insert(str);
        System.out.println(str+" Added");
        Intent intent = new Intent(LView.this, MyList.class);
        startActivity(intent);              
    }
});`

`

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // TODO Auto-generated method stub
    super.onActivityResult(requestCode, resultCode, data);
    switch(requestCode) {

    case 1: 
        if(resultCode == RESULT_OK) {
            Uri selectedUri = data.getData();
            str = getPath(selectedUri);
            Bitmap bitmap;              
            try {                   
                bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedUri));
                mAlbum.setImageBitmap(bitmap);
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            break;
            }
        }
}
// Converting image path Uri to String path to store in DB
    public String getPath(Uri uri) {
        String[] projection = { MediaStore.Images.Media.DATA };
        Cursor cur = managedQuery(uri, projection, null, null, null);
        int columnIndex = cur.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cur.moveToFirst();

        return cur.getString(columnIndex);
    }`

请建议我...... 提前谢谢。

3 个答案:

答案 0 :(得分:9)

1)尝试解码首先绑定的图像

您可以获得图像的实际大小以防止出现OOM问题。不要先解码图像!!!

    BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;

BitmapFactory.decodeByteArray(bitmapByteArray, 0, bitmapByteArray.length, options);'

options.outWidth和options.outHeight就是你想要的。

2)计算样本量

使用http://hi-android.info/src/com/android/camera/Util.java.html中的以下代码。如果检测到outWidth并且outHeight太大而无法解决OOM问题,只需将outWidth和outHeight设置为较小的大小即可。它将为您提供一个样本大小,解码后的图像将被设置为outWidth和outHeight。此处的位图选项与您在步骤1中使用的相同。

    private static int computeInitialSampleSize(BitmapFactory.Options options,
        int minSideLength, int maxNumOfPixels) {
    double w = options.outWidth;
    double h = options.outHeight;

    int lowerBound = (maxNumOfPixels == IImage.UNCONSTRAINED) ? 1 :
            (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
    int upperBound = (minSideLength == IImage.UNCONSTRAINED) ? 128 :
            (int) Math.min(Math.floor(w / minSideLength),
            Math.floor(h / minSideLength));

    if (upperBound < lowerBound) {
        // return the larger one when there is no overlapping zone.
        return lowerBound;
    }

    if ((maxNumOfPixels == IImage.UNCONSTRAINED) &&
            (minSideLength == IImage.UNCONSTRAINED)) {
        return 1;
    } else if (minSideLength == IImage.UNCONSTRAINED) {
        return lowerBound;
    } else {
        return upperBound;
    }
}

3)使用计算出的样本量

获得样本量后,使用它来解码实际图像数据。

            options.inTempStorage = new byte[16*1024];
        options.inPreferredConfig = (config == null)?BitmapUtil.DEFAULT_CONFIG:config;
        options.inSampleSize = BitmapUtil.computeSampleSize(bitmapWidth, bitmapHeight, bitmapWidth < bitmapHeight?targetHeight:targetWidth, bitmapWidth < bitmapHeight?targetWidth:targetHeight, 1);
        options.inPurgeable = true;  
        options.inInputShareable = true;  
        options.inJustDecodeBounds = false;
        options.inDither = true;
        result = BitmapFactory.decodeByteArray(bitmapByteArray, 0, bitmapByteArray.length, options);

〜如果这仍然给你OOM问题,你可以尝试降低outWidth和outHeight。 位图使用的是本机堆,而不是java堆。因此很难检测到解码的新图像剩余多少内存。


~~如果你必须设置outWidth和outHeight太低,那么你的代码中可能会有内存泄漏。尝试从你不使用的内存中释放任何对象。 e.g bitmap.release();


~~~以上只是一个示例代码。调整你需要的东西。

答案 1 :(得分:2)

答案 2 :(得分:0)

您是否尝试过使用一个类范围的Bitmap并在case子句中重新分配它?