Skip to content
This repository has been archived by the owner on Nov 8, 2023. It is now read-only.

Commit

Permalink
Make animators more robust against ending mid-stream
Browse files Browse the repository at this point in the history
The logic in the frame processing code of ValueAnimator did not handle
the situation of animators being ended while the current animation list
was being processed. In particular, if a call to an animation update
(which could result in a call out to user code) caused that animation, or
other current animators, to end, then there was the risk of running off the
end of the list of current animators.

The fix is to work from a copy of the current animator list, processing frames
on each one only if they also exist in the real animations list.

Issue #6992223 Frequent System UI crash

Change-Id: I742964558f8354f04c311b7b51c7686f26a4dacf
  • Loading branch information
chethaase committed Aug 16, 2012
1 parent 6b7d46b commit 2936fc0
Showing 1 changed file with 11 additions and 18 deletions.
29 changes: 11 additions & 18 deletions core/java/android/animation/ValueAnimator.java
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,9 @@ private static class AnimationHandler implements Runnable {
// The per-thread list of all active animations
private final ArrayList<ValueAnimator> mAnimations = new ArrayList<ValueAnimator>();

// Used in doAnimationFrame() to avoid concurrent modifications of mAnimations
private final ArrayList<ValueAnimator> mTmpAnimations = new ArrayList<ValueAnimator>();

// The per-thread set of animations to be started on the next animation frame
private final ArrayList<ValueAnimator> mPendingAnimations = new ArrayList<ValueAnimator>();

Expand Down Expand Up @@ -605,28 +608,18 @@ private void doAnimationFrame(long frameTime) {
// Now process all active animations. The return value from animationFrame()
// tells the handler whether it should now be ended
int numAnims = mAnimations.size();
int i = 0;
while (i < numAnims) {
ValueAnimator anim = mAnimations.get(i);
if (anim.doAnimationFrame(frameTime)) {
for (int i = 0; i < numAnims; ++i) {
mTmpAnimations.add(mAnimations.get(i));
}
for (int i = 0; i < numAnims; ++i) {
ValueAnimator anim = mTmpAnimations.get(i);
if (mAnimations.contains(anim) && anim.doAnimationFrame(frameTime)) {
mEndingAnims.add(anim);
}
if (mAnimations.size() == numAnims) {
++i;
} else {
// An animation might be canceled or ended by client code
// during the animation frame. Check to see if this happened by
// seeing whether the current index is the same as it was before
// calling animationFrame(). Another approach would be to copy
// animations to a temporary list and process that list instead,
// but that entails garbage and processing overhead that would
// be nice to avoid.
--numAnims;
mEndingAnims.remove(anim);
}
}
mTmpAnimations.clear();
if (mEndingAnims.size() > 0) {
for (i = 0; i < mEndingAnims.size(); ++i) {
for (int i = 0; i < mEndingAnims.size(); ++i) {
mEndingAnims.get(i).endAnimation(this);
}
mEndingAnims.clear();
Expand Down

0 comments on commit 2936fc0

Please sign in to comment.