Merge "Fix leak in LayoutTransition" into mnc-dev

This commit is contained in:
Chet Haase
2015-05-07 16:56:42 +00:00
committed by Android (Google) Code Review

View File

@ -28,6 +28,7 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* This class enables automatic animations on layout changes in ViewGroup objects. To enable
@ -757,7 +758,7 @@ public class LayoutTransition {
// reset the inter-animation delay, in case we use it later
staggerDelay = 0;
final ViewTreeObserver observer = parent.getViewTreeObserver(); // used for later cleanup
final ViewTreeObserver observer = parent.getViewTreeObserver();
if (!observer.isAlive()) {
// If the observer's not in a good state, skip the transition
return;
@ -790,21 +791,9 @@ public class LayoutTransition {
// This is the cleanup step. When we get this rendering event, we know that all of
// the appropriate animations have been set up and run. Now we can clear out the
// layout listeners.
observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
parent.getViewTreeObserver().removeOnPreDrawListener(this);
int count = layoutChangeListenerMap.size();
if (count > 0) {
Collection<View> views = layoutChangeListenerMap.keySet();
for (View view : views) {
View.OnLayoutChangeListener listener = layoutChangeListenerMap.get(view);
view.removeOnLayoutChangeListener(listener);
}
}
layoutChangeListenerMap.clear();
return true;
}
});
CleanupCallback callback = new CleanupCallback(layoutChangeListenerMap, parent);
observer.addOnPreDrawListener(callback);
parent.addOnAttachStateChangeListener(callback);
}
/**
@ -1499,4 +1488,50 @@ public class LayoutTransition {
View view, int transitionType);
}
/**
* Utility class to clean up listeners after animations are setup. Cleanup happens
* when either the OnPreDrawListener method is called or when the parent is detached,
* whichever comes first.
*/
private static final class CleanupCallback implements ViewTreeObserver.OnPreDrawListener,
View.OnAttachStateChangeListener {
final Map<View, View.OnLayoutChangeListener> layoutChangeListenerMap;
final ViewGroup parent;
CleanupCallback(Map<View, View.OnLayoutChangeListener> listenerMap, ViewGroup parent) {
this.layoutChangeListenerMap = listenerMap;
this.parent = parent;
}
private void cleanup() {
parent.getViewTreeObserver().removeOnPreDrawListener(this);
parent.removeOnAttachStateChangeListener(this);
int count = layoutChangeListenerMap.size();
if (count > 0) {
Collection<View> views = layoutChangeListenerMap.keySet();
for (View view : views) {
View.OnLayoutChangeListener listener = layoutChangeListenerMap.get(view);
view.removeOnLayoutChangeListener(listener);
}
layoutChangeListenerMap.clear();
}
}
@Override
public void onViewAttachedToWindow(View v) {
}
@Override
public void onViewDetachedFromWindow(View v) {
cleanup();
}
@Override
public boolean onPreDraw() {
cleanup();
return true;
}
};
}