Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Only Android 4.1, Bitmap is recycled automatically

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

like image 233
user1746071 Avatar asked Oct 15 '12 06:10

user1746071


2 Answers

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.

like image 102
XdebugX Avatar answered Nov 20 '22 13:11

XdebugX


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;
}
like image 37
JRomero Avatar answered Nov 20 '22 12:11

JRomero