如何解决这个错误:java.lang.OutOfMemoryError: bitmap size exceeds VM budget

4

我正在尝试将图像添加到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个回答

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"。这里的位图选项与步骤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的值。Bitmap使用的是本地堆而不是Java堆,所以很难检测新解码图像还剩下多少内存。


如果你不得不将outWidth和outHeight设置得太低,那么你可能在代码中有内存泄漏。尝试释放任何你不使用的对象,例如bitmap.release();


以上仅为示例代码,根据需要进行相应调整。


2

嗨,不不……我还在遇到问题……如果问题得到解决,我一定会为您点赞……抱歉耽搁了——PolamReddy - Ria
虽然此链接可能回答问题,但最好在此处包含答案的重要部分并提供引用链接。仅有链接的答案可能会因链接页面的更改而变得无效。 - ProgramFOX

0

你尝试过在case子句中使用一个类范围的位图并重新分配它吗?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接