jas7457
jas7457

Reputation: 1991

I'm getting OutOfMemory errors sometimes with my Bitmap-heavy Android application

I'm making an android app that is very picture-oriented, thus I'm using a lot of Bitmaps. I know that it is good practice to use Bitmap.recycle(); to help with garbage collection, but the rest of my app is not allowing me to do so.

I made a class called URLImageView that extends ImageView which allows you to set the image from a URL. I have another class that I found online called SlidingUpPanelLayout which extends ViewGroup, and if I call Bitmap.recycle();, I get an error saying that it can't draw recycled bitmaps.

Can anyone think of a good work-around so that I free up resources, but still have them available for the SlidingUpPanelLayout?

Below is the URLImageView class that I created.

public class URLImageView extends ImageView
{
private ImageLoadTask task = null;
public URLImageView(Context context)
{
    this(context, null, 0);
}

public URLImageView(Context context, AttributeSet attrs)
{
    this(context, attrs, 0);
}

public URLImageView(Context context, AttributeSet attrs, int defStyle)
{
    super(context, attrs, defStyle);
}

public void setImageFromURL(String url)
{
    //System.gc();
    Bitmap bitmap = ImageCache.getBitmapFromCache(url);
    if(bitmap == null)//the bitmap was not found in the cache, so let's actually build it
    {
        if(task != null)
            task.cancel(true);
        task = new ImageLoadTask();

        if(Build.VERSION.SDK_INT >= 11)//load the images in parallel instead of waiting
        {
            task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url);
        } 
        else //too bad. we have to load them in series :(
        {
            task.execute(url);
        }
    }
    else//the bitmap was in the cache, so just set it
    {
        this.setImageBitmap(bitmap);
    }

    //if(bitmap != null)
    //  bitmap.recycle();
    bitmap = null;
}

private class ImageLoadTask extends AsyncTask<String, String, Bitmap>
{
    private String url;

    @Override
    protected void onPreExecute()
    {
        setImageResource(R.drawable.blank);
    }

    @Override
    protected Bitmap doInBackground(String... args)
    {
        try
        {
            //System.gc();
            url = args[0];
            Bitmap bitmap = BitmapFactory.decodeStream((InputStream)new URL(url).getContent());
            return bitmap;
        }

        catch (Exception e)
        {
            return null;
        }
    }

    @Override
    protected void onPostExecute(Bitmap bitmap)
    {
        //System.out.println("onPostExecute...");
        if(bitmap != null)
        {
            ImageCache.addBitmapToCache(url, bitmap);
            URLImageView.this.setImageBitmap(bitmap);

            //bitmap.recycle();
            bitmap = null;
        }

        else
        {
            setImageResource(R.drawable.blank);
        }
        task = null;
    }
}
}

Upvotes: 1

Views: 158

Answers (2)

MohK
MohK

Reputation: 1933

This is because of large bitmap which occupies everything in RAM . :D

You can load a scaled image, which will decrease a lot the memory usage, but you have to know your images to not lose too much quality of it.

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);

Reference: http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html

Upvotes: 2

Pulkit Sethi
Pulkit Sethi

Reputation: 1325

use this function http://developer.android.com/reference/android/graphics/Bitmap.html#createBitmap(android.graphics.Bitmap, int, int, int, int) then u dont need to recycle. if u cant downsize use lrucache

Upvotes: 1

Related Questions