From 1a76dcd6d1e30f92668b5df309398d545cef9ace Mon Sep 17 00:00:00 2001 From: Chet Haase Date: Thu, 6 Oct 2011 11:16:40 -0700 Subject: [PATCH] Fix issue #5367164: memory leak in LayoutTransition When a transition occurs, layout change listeners are added to the container being transitioned as well as every container up the view hierarchy. The parent views were not having those listeners removed, so every time a transition ran, more listeners would be added. Adding to that, the use of an ArrayList as the collection to hold the listeners meant that adding duplicate items would just increase the size of the list. There's now a sanity-check on the add call to make sure that the listener does not exist already, but more importantly we remove all listeners added when the transition ends. Change-Id: I4ea05adf30765db091124065539b0ffd32729b3b --- core/java/android/animation/LayoutTransition.java | 12 ++++++++---- core/java/android/view/View.java | 4 +++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java index 355b1fcc68ded..f383af93851ed 100644 --- a/core/java/android/animation/LayoutTransition.java +++ b/core/java/android/animation/LayoutTransition.java @@ -24,6 +24,7 @@ import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.DecelerateInterpolator; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; @@ -615,10 +616,13 @@ public class LayoutTransition { observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { public boolean onPreDraw() { parent.getViewTreeObserver().removeOnPreDrawListener(this); - int numChildren = parent.getChildCount(); - for (int i = 0; i < numChildren; ++i) { - final View child = parent.getChildAt(i); - child.removeOnLayoutChangeListener(layoutChangeListenerMap.get(child)); + int count = layoutChangeListenerMap.size(); + if (count > 0) { + Collection views = layoutChangeListenerMap.keySet(); + for (View view : views) { + View.OnLayoutChangeListener listener = layoutChangeListenerMap.get(view); + view.removeOnLayoutChangeListener(listener); + } } layoutChangeListenerMap.clear(); return true; diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 8e5aefdff0e86..632ab4acb25e7 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -3335,7 +3335,9 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal if (mOnLayoutChangeListeners == null) { mOnLayoutChangeListeners = new ArrayList(); } - mOnLayoutChangeListeners.add(listener); + if (!mOnLayoutChangeListeners.contains(listener)) { + mOnLayoutChangeListeners.add(listener); + } } /**