Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
339 views
in Technique[技术] by (71.8m points)

android - How to overcome this error:java.lang.OutOfMemoryError: bitmap size exceeds VM budget

I am trying to add images in Sqlite DB and listing the images from DB to listview.... I am storing the image path to get image. When I list the images from DB in device I am getting error like java.lang.OutOfMemoryError: bitmap size exceeds VM budget

Do I clear heap memory every time. How to correct this.. Here is my code.

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);
    }`

Pls suggest me... Thanks in advance.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

1) try to decode the image bound first

you get the actual size of the image to prevent the OOM issue. Dont ever decode the image first!!!

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

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

options.outWidth and options.outHeight are what you want.

2) compute a sample size

by using the following code from http://hi-android.info/src/com/android/camera/Util.java.html. If you detect the outWidth and outHeight are too big to have OOM issue, just set the outWidth and outHeight to a smaller size. It will give you a sample size that the decoded image will be set to those outWidth and outHeight. The bitmap options here is the same you use in step 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) Use the computed sample size

Once you get the sample size, use it to decode the real image data.

            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);

~If this still give you OOM issue, you can try to lower the outWidth and outHeight. bitmap is using native heap, not the java heap. So it is hard to detect how much memory left for the new image decoded.


~~If you have to set the outWidth and outHeight too low, then you may have memory leak somewhere in your code. try to release any object from memory that you dont use. e.g bitmap.release();


~~~the above is just a sample code. adjust what you need.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...