Out Of Memory Exceptions when using Images in Android

I haven’t talked about my app for a while. The development was going quite well. When the learning phase of working with android was decreasing, the development effort decreased and I started to embrace the android development framework and its lifecycle.
The functionality of my app increased rapidly, with tons of new features and the look and feel got better and better and better (thanks to www.fierkant.nl!)

That’s when random crashes of my app start to occur at random moments in the app.
The debugger couldn’t help me at all and all I got was this exception message:

 Out of memory: Heap Size=49159KB, Allocated=40884KB, Limit=49152KB

I couldn’t really figure out why, I did use some memory by drawing some images, but it wasn’t huge.
So I googled it and it seems to be a common problem. A lot of people run in to these Memory issues.

The garbage collector collects all elements which are not used. Unfortunately, the views have a callback, this is why the garbage collector cannot detect that they aren’t used anymore.

I found some code which unbinds all views and their descendants. I tweaked it a bit and rewrote it for c#.

protected void UnbindDrawables(View view)
{
   if (view == null) { return; }

  if (view.Background != null)
  {
      view.Background.Callback = null;
  }
  if (view is ViewGroup)
  {
       for (int i = 0; i < ((ViewGroup)view).ChildCount; i++)
       {
           UnbindDrawables(((ViewGroup)view).GetChildAt(i));
       }
       if (!(view is AdapterView))
       {
           ((ViewGroup)view).RemoveAllViews();
      }
  }
}

Now that we’ve got this method, we can call it in the OnDestroy of an Activity.
In this example, I use my LayoutContainer view, which is my outer wrapper view which contains all views of the current layout. Feel free to use your own view id, but make sure the images you want to unbind are in this view.

protected override void OnDestroy()
{
   base.OnDestroy();

   UnbindDrawables(FindViewById<RelativeLayout>(Resource.Id.LayoutContainer));
   System.GC.Collect();
}

When I implemented this in all activities (perhaps consider a BaseActivity), the memory issues were gone and I have not seen them since.
A lot of people suggest to add android:largeHeap=”true” to your manifest file so your app can use more heap size. I don’t consider that as a good solution. You should try to keep your application clean and only use the memory you really need. Just clean everything up as you’re supposed to.

The following two tabs change content below.
I'm a software developer from Utrecht. Interested in DDD, continuous delivery, new technologies & frameworks.

Latest posts by Vincent Keizer (see all)

1 Comment

  1. Thanks for this great Answer. I didn’t try this. But I have to do it, because I’m facing too much OOM issue. In my all activity it is applicable, but not in my MainScreen. Because that screen is never getting destroyed. My main screen has listview and that listview has ViewPager as a item and each view pager contains 4-5 images (with OffScreenLimit = 1 and imageWidth & imageHeight = ScreenWidth). So how can I free up the space.

Leave a Reply

Your email address will not be published.

*