2

I'm a fairly new programmer so any advice would be appreciated. I have a class that runs an AsyncTask in a loop everytime it is called. The AsyncTask looks like this:

public class LoadImageTask extends AsyncTask<Void, Void, Void> {

    Context c;
    ViewHolder vh;
    public Bitmap bm;
    ViewGroup container;
    LinearLayout layout;

    public LoadImageTask(Context c, ViewHolder vh, ViewGroup container, 
    LinearLayout linlay) {

        this.vh = vh;
        this.c = c;
        this.container = container;
        this.layout = linlay;
    }

    protected Void doInBackground(Void... params) {
        Tools tools = new Tools();
        this.bm = tools.getAlbumart(this.c, vh.albumID);
        return null;
    }

    protected void onPostExecute(Void param) {
        vh.iv.setImageBitmap(this.bm);
        this.layout.addView(this.container);
        if (bm!=null) {
            bm.recycle();
        }

    }
}

ViewHolder vh - class that holds 2 textviews and an Imageview

ViewGroup container - the container being used to inflate an xml design i've made (with 2 textviews and an ImageView)

LinearLayout linlay - a scrollview layout that I am adding the container to (to expand it based on the amount of elements I want in that view)

The bitmaps that I create as using way too much memory, so I want to recycle them, but every time I try to recycle them after I add the container to the layout, it says I am trying to use a recycled bitmap (when I'm clearly calling recycle after adding the container to the screen)... I'm stumped at this point. Any help would be nice.

EvanYounan
  • 35
  • 1
  • 11

2 Answers2

3

At the moment you are recycling the bitmap before it has been rendered onto the UI, since setImageBitmap(bm) will only prepare the ImageView for rendering the supplied Bitmap. The render will be scheduled for the next invalidation of the UI.

bm.recycle() gets called before the Bitmap has been rendered, so the app will crash when trying to draw the Bitmap.

You cannot recycle the Bitmap while using it on in the UI, the Bitmap has to be kept in memory. Android will in most cases handle recycling just fine, but if you need to recycle yourself you need to make sure to not use the Bitmap instance afterwards (as in this case where the Bitmap instance will be rendered later on).

Pär Nils Amsen
  • 755
  • 5
  • 16
  • So, what my app is doing is creating a bunch of Song objects (which are initialized beforehand). Then for each song it sets the textviews and imageviews based on the song's given characteristics. For each song that I am processing, I run the AsyncTask, so I end up having a large number of bitmaps (same number of songs with images) so I need a way to recycle them after they are drawn or else too much memory is being used. Do I have the wrong approach? – EvanYounan May 03 '17 at 10:13
  • Not necessarily, it's a matter of optimization. You have enough RAM to load a little bit more than the pixels on the device screen on most devices, for album art of 200x200px thats roughly 8 albums in memory at once for a newer phone. My advice would be to use a RecyclerView and lazy load the images as they are to be showed on the screen, also make sure that you are using appropriately scaled images (not 800x800 while only 50x50 is needed). To aid with all this, use http://square.github.io/picasso/ to load the images lazily, it's a great image loading lib that honors RAM usage. – Pär Nils Amsen May 03 '17 at 10:17
  • 1
    Awesome! I'm definitely going to make use of the lazy loading and RecycleView. Thanks a lot for the tips! – EvanYounan May 03 '17 at 11:46
  • 1
    You seriously saved my life! – Marc Alexander Sep 28 '18 at 19:13
0
  1. If bitmap using too much memory you should try to scale it down! (Ex: Albumart with 256x256 is good choice)

  2. If you run your app on Android 3.0 and above, it's not needed to call recycle() as the GC will take care of it perfectly.

  3. See Pär Nils Amsen answer.

squalle0nhart
  • 351
  • 1
  • 6
  • Oh wow! Creating another scaled bitmap and recycling the original one fixed the problem! Scaling it down really did help, Thanks! – EvanYounan May 03 '17 at 10:26