Merge "Fix leak with transitions when views get removed" into klp-dev

This commit is contained in:
Chet Haase
2013-10-23 19:17:09 +00:00
committed by Android (Google) Code Review
3 changed files with 102 additions and 49 deletions

View File

@@ -994,15 +994,7 @@ public abstract class Transition implements Cloneable {
* false otherwise
*/
void captureValues(ViewGroup sceneRoot, boolean start) {
if (start) {
mStartValues.viewValues.clear();
mStartValues.idValues.clear();
mStartValues.itemIdValues.clear();
} else {
mEndValues.viewValues.clear();
mEndValues.idValues.clear();
mEndValues.itemIdValues.clear();
}
clearValues(start);
if (mTargetIds.size() > 0 || mTargets.size() > 0) {
if (mTargetIds.size() > 0) {
for (int i = 0; i < mTargetIds.size(); ++i) {
@@ -1054,6 +1046,23 @@ public abstract class Transition implements Cloneable {
}
}
/**
* Clear valuesMaps for specified start/end state
*
* @param start true if the start values should be cleared, false otherwise
*/
void clearValues(boolean start) {
if (start) {
mStartValues.viewValues.clear();
mStartValues.idValues.clear();
mStartValues.itemIdValues.clear();
} else {
mEndValues.viewValues.clear();
mEndValues.idValues.clear();
mEndValues.itemIdValues.clear();
}
}
/**
* Recursive method which captures values for an entire view hierarchy,
* starting at some root view. Transitions without targetIDs will use this

View File

@@ -19,6 +19,7 @@ package android.transition;
import android.content.Context;
import android.util.ArrayMap;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
@@ -205,48 +206,91 @@ public class TransitionManager {
private static void sceneChangeRunTransition(final ViewGroup sceneRoot,
final Transition transition) {
if (transition != null) {
final ViewTreeObserver observer = sceneRoot.getViewTreeObserver();
final ViewTreeObserver.OnPreDrawListener listener =
new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
sPendingTransitions.remove(sceneRoot);
// Add to running list, handle end to remove it
final ArrayMap<ViewGroup, ArrayList<Transition>> runningTransitions =
getRunningTransitions();
ArrayList<Transition> currentTransitions = runningTransitions.get(sceneRoot);
ArrayList<Transition> previousRunningTransitions = null;
if (currentTransitions == null) {
currentTransitions = new ArrayList<Transition>();
runningTransitions.put(sceneRoot, currentTransitions);
} else if (currentTransitions.size() > 0) {
previousRunningTransitions = new ArrayList<Transition>(currentTransitions);
}
currentTransitions.add(transition);
transition.addListener(new Transition.TransitionListenerAdapter() {
@Override
public void onTransitionEnd(Transition transition) {
ArrayList<Transition> currentTransitions =
runningTransitions.get(sceneRoot);
currentTransitions.remove(transition);
}
});
transition.captureValues(sceneRoot, false);
if (previousRunningTransitions != null) {
for (Transition runningTransition : previousRunningTransitions) {
runningTransition.resume();
}
}
transition.playTransition(sceneRoot);
return true;
}
};
observer.addOnPreDrawListener(listener);
if (transition != null && sceneRoot != null) {
MultiListener listener = new MultiListener(transition, sceneRoot);
sceneRoot.addOnAttachStateChangeListener(listener);
sceneRoot.getViewTreeObserver().addOnPreDrawListener(listener);
}
}
/**
* This private utility class is used to listen for both OnPreDraw and
* OnAttachStateChange events. OnPreDraw events are the main ones we care
* about since that's what triggers the transition to take place.
* OnAttachStateChange events are also important in case the view is removed
* from the hierarchy before the OnPreDraw event takes place; it's used to
* clean up things since the OnPreDraw listener didn't get called in time.
*/
private static class MultiListener implements ViewTreeObserver.OnPreDrawListener,
View.OnAttachStateChangeListener {
Transition mTransition;
ViewGroup mSceneRoot;
MultiListener(Transition transition, ViewGroup sceneRoot) {
mTransition = transition;
mSceneRoot = sceneRoot;
}
private void removeListeners() {
mSceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
mSceneRoot.removeOnAttachStateChangeListener(this);
}
@Override
public void onViewAttachedToWindow(View v) {
}
@Override
public void onViewDetachedFromWindow(View v) {
removeListeners();
sPendingTransitions.remove(mSceneRoot);
ArrayList<Transition> runningTransitions = getRunningTransitions().get(mSceneRoot);
if (runningTransitions != null && runningTransitions.size() > 0) {
for (Transition runningTransition : runningTransitions) {
runningTransition.resume();
}
}
mTransition.clearValues(true);
}
@Override
public boolean onPreDraw() {
removeListeners();
sPendingTransitions.remove(mSceneRoot);
// Add to running list, handle end to remove it
final ArrayMap<ViewGroup, ArrayList<Transition>> runningTransitions =
getRunningTransitions();
ArrayList<Transition> currentTransitions = runningTransitions.get(mSceneRoot);
ArrayList<Transition> previousRunningTransitions = null;
if (currentTransitions == null) {
currentTransitions = new ArrayList<Transition>();
runningTransitions.put(mSceneRoot, currentTransitions);
} else if (currentTransitions.size() > 0) {
previousRunningTransitions = new ArrayList<Transition>(currentTransitions);
}
currentTransitions.add(mTransition);
mTransition.addListener(new Transition.TransitionListenerAdapter() {
@Override
public void onTransitionEnd(Transition transition) {
ArrayList<Transition> currentTransitions =
runningTransitions.get(mSceneRoot);
currentTransitions.remove(transition);
}
});
mTransition.captureValues(mSceneRoot, false);
if (previousRunningTransitions != null) {
for (Transition runningTransition : previousRunningTransitions) {
runningTransition.resume();
}
}
mTransition.playTransition(mSceneRoot);
return true;
}
};
private static void sceneChangeSetup(ViewGroup sceneRoot, Transition transition) {
// Capture current values

View File

@@ -65,7 +65,7 @@ public class KeyguardTransportControlView extends FrameLayout {
protected static final boolean DEBUG = false;
protected static final String TAG = "TransportControlView";
private static final boolean ANIMATE_TRANSITIONS = false;
private static final boolean ANIMATE_TRANSITIONS = true;
private ViewGroup mMetadataContainer;
private ViewGroup mInfoContainer;