2

two days ago i noticed something. I have a spinner over a map activity. In the OnCreate() method of the activity i populate the spinner with data. After that i start the heap analyzer in DDMS i begin to open/close the spinner. I noticed the VM allocate memory when i open the spinner items, but when i close it, the VM do no free this memory. I've tried to start the GC, but the memory is still allocated. i did this 20 times one by one and the allocated memory increased from 3.5MB to 7MB. What is wrong? I found an issue in google groups, but they haven't answered yet.
Spinner memory leak

I rewrite all my code in the spinner adapter, but the issue still remains. I read some advices in this topic

Avoid memory leaks

There is something i did not get:

When a Drawable is attached to a view, the view is set as a callback on the drawable. In the code snippet above, this means the drawable has a reference to the TextView which itself has a reference to the activity (the Context) which in turns has references to pretty much anything (depending on your code.)

What does it mean? If i have a textview and set it a drawable object (i noticed the drawable is static), the textview object has a reference to the drawable object and the drawable object has a reference to the view too? If this is true, they become undestroyable by the GC because they both have references to each other? What is this back-reference (callbacks) dependencе between the objects?

Plamen Nikolov
  • 4,177
  • 3
  • 23
  • 24

1 Answers1

19

Sorry I can't help you on your Spinner problem but I can have a try on the second part:

Romain Guy post on android developer blog explain two important things.

First:

When you create a View (TextView, ImageView...) you must not create it with the activity Context

// DO NOT DO THIS
TextView label = new TextView(this);

Otherwise the View get a reference to your activity and will never be deallocated.

Instead, when you create a View programatically, you have to use the application context:

TextView label = new TextView(getApplicationContext());

Second:

When you link a Drawable to an View, it keeps a callback on your activity via the Context. If you leave it, it will leak memory when your activity is destroy.

The thing to do to avoid that is to "set stored drawables' callbacks to null when the activity is destroyed" so for example whith an ImageView:

protected void onDestroy() {
    imageView.getDrawable().setCallback(null);
    super.onDestroy();
}

You have to do the same for the background drawable...

Hope it helps.

ol_v_er
  • 27,094
  • 6
  • 48
  • 61
  • 2
    "When you link a Drawable to an View, it keeps a callback on your activity via the Context." ---> ***this is incorrect***. the callback is on the view. (its the View that implements the Drawable.Callback interface not Activity) – numan salati May 12 '13 at 22:58
  • @ol_v_er Can you share the link where Romain Guy explained this ? – Priya Singhal Mar 23 '16 at 12:38
  • I think I found the link : http://www.curious-creature.com/2008/12/18/avoid-memory-leaks-on-android/ – Priya Singhal Mar 23 '16 at 12:41
  • Notably, `protected Context mContext;` is a reference on `View` (strong, because it is not using `WeakReference`. – Ben Butterworth Feb 06 '21 at 14:42
  • the link is now down, but the Wayback machine has it [here](https://web.archive.org/web/20171116104019/http://www.curious-creature.com/2008/12/18/avoid-memory-leaks-on-android/). – Ben Butterworth Feb 06 '21 at 14:43
  • @ol_v_er, `mCallback` (the callback reference) on drawable is actually a WeakReference though, `private WeakReference mCallback = null;`, so am I right in thinking this should not cause a memory leak? – Ben Butterworth Feb 06 '21 at 14:44
  • Yea, so the OP no longer has a memory leak since 2010. I address this in my answer [here](https://stackoverflow.com/questions/11954572/why-does-drawable-have-a-reference-to-a-view/66078037#66078037). – Ben Butterworth Feb 06 '21 at 15:02