Only Android 4.1, Bitmap is recycled automatically
Asked Answered
C

3

5

I've got very critical problem. Only Android 4.1, Bitmap is recycled automatically! I didn't call recycle() in my code! My project works fine in other OS versions( ~ 4.0.3) with any resolutions. Other projects have same problem, too.

All image files are in drawable-nodpi folder. I resized them to fit for resolution of any devices, always.

public Bitmap GetBitmap(int resource){

    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inDither = true;
    options.inPurgeable = true;

    Bitmap tmp = null;

    try{
        tmp = BitmapFactory.decodeResource(mResources, resource, options);
    }catch(OutOfMemoryError e){
        options.inSampleSize = 2;
        tmp = BitmapFactory.decodeResource(mResources, resource, options);
    }

    return tmp;
}

public Bitmap GetScaledBitmap(int resource, int width, int height, boolean filter){

    Bitmap tmp = GetBitmap(resource);

    Bitmap img = Bitmap.createScaledBitmap(tmp, width, height, filter);

    tmp.recycle();
    tmp = null;

    return img;
}

In my testing,

  • Same bitmap instance, but the problem occurs depending on resizing value.

ex) int width = 100;

Bitmap imgStar = MyResourceManager.getInstance().GetScaledBitmap(R.drawable.star, width, width , true); -> returns recycled instance.

width = 200;

imgStar = MyResourceManager.getInstance().GetScaledBitmap(R.drawable.star, width, width, true); -> returns normal instance.

  • In different resolutions, imgStar works fine, but the problem occurs in other bitmap instance. Similarly, When I change resizing value, it works fine.

  • In same resolution, the problem occurs in other bitmap instance, if I change the name of image files folder. drawable-nodpi -> drawable -> drawable-ldpi, ..., drawable-xdpi.

  • Same resizing value, it works fine if I put other resource id. ex)

int width = 100;

Bitmap imgStar = MyResourceManager.getInstance().GetScaledBitmap(R.drawable.star, width, width , true); -> returns recycled instance.

imgStar = MyResourceManager.getInstance().GetScaledBitmap(R.drawable.diamond, width, width, true); -> returns normal instance.

Please... what can I do?! T ^ T

Chongchoo answered 15/10, 2012 at 6:56 Comment(1)
This question is similar and may have your answer: #7983821Watchword
W
6

The reason you're getting different results from different sizes may be because createScaledBitmap will return the original object if it is the same size you are scaling to.

I had the same problem, doing the same thing you are. I was able to fix it this way:

public Bitmap GetScaledBitmap(int resource, int width, int height, boolean filter) {

    Bitmap tmp = GetBitmap(resource);
    Bitmap img = Bitmap.createScaledBitmap(tmp, width, height, filter);
    //copy the image to be sure you are not using the same object as the tmp bitmap
    img=img.copy (Bitmap.Config.RGB_565,false);
    tmp.recycle();
    tmp = null;
    return img;
}

Here I copied the bitmap to make sure it wasn't just a refernce to the tmp bitmap object before I recycled the tmp bitmap. Of course you can use any bitmap config you need.

Watchword answered 6/12, 2012 at 1:34 Comment(0)
T
2

I believe XdebugX was correct in his finding although you don't need to create a copy. Simply check if the memory locations are the same between your resized and original bitmaps.

public Bitmap GetScaledBitmap(int resource, int width, int height, boolean filter){

    Bitmap tmp = GetBitmap(resource);
    if (tmp == null) {
        return null;
    }

    Bitmap img = Bitmap.createScaledBitmap(tmp, width, height, filter);

    /***
     * Bitmap#createScaledBitmap will return the original object
     * if it is the same size you are scaling to.
     */
    if (tmp != img) {
        Log.d(TAG, "Full size image recycled");
        tmp.recycle();
    } else {
        Log.w(TAG, "Resized bitmap was the same as the fullsize bitmap");
    }

    return img;
}
Tonedeaf answered 7/6, 2013 at 18:56 Comment(0)
K
0

I'd rather suggest to try checking if the bitmap is already recycled before to recycle:

if (!tmp.isRecycled()) tmp.recycle();
Karim answered 9/1, 2013 at 15:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.