diff options
author | Jeff Brown <jeffbrown@google.com> | 2011-12-02 16:22:46 -0800 |
---|---|---|
committer | Jeff Brown <jeffbrown@google.com> | 2011-12-05 11:16:06 -0800 |
commit | 9c38dbeb1d183ecd48bbf5d18a39f5e0508a1223 (patch) | |
tree | 57108beec2c0526796034b79d3ad6a2833ff5712 | |
parent | 315e468763c9601e2f06443fda847d2c9eb27a75 (diff) | |
download | frameworks_base-9c38dbeb1d183ecd48bbf5d18a39f5e0508a1223.zip frameworks_base-9c38dbeb1d183ecd48bbf5d18a39f5e0508a1223.tar.gz frameworks_base-9c38dbeb1d183ecd48bbf5d18a39f5e0508a1223.tar.bz2 |
Refactor ValueAnimator to reduce use of ThreadLocals.
Change-Id: I494c9cc32e58b77d5f7ea092ee6a0ae4d2d805bb
-rwxr-xr-x | core/java/android/animation/ValueAnimator.java | 145 |
1 files changed, 58 insertions, 87 deletions
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index edd0fa3..4f63165 100755 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -83,70 +83,15 @@ public class ValueAnimator extends Animator { */ long mSeekTime = -1; - // TODO: We access the following ThreadLocal variables often, some of them on every update. - // If ThreadLocal access is significantly expensive, we may want to put all of these - // fields into a structure sot hat we just access ThreadLocal once to get the reference - // to that structure, then access the structure directly for each field. - // The static sAnimationHandler processes the internal timing loop on which all animations // are based private static ThreadLocal<AnimationHandler> sAnimationHandler = new ThreadLocal<AnimationHandler>(); - // The per-thread list of all active animations - private static final ThreadLocal<ArrayList<ValueAnimator>> sAnimations = - new ThreadLocal<ArrayList<ValueAnimator>>() { - @Override - protected ArrayList<ValueAnimator> initialValue() { - return new ArrayList<ValueAnimator>(); - } - }; - - // The per-thread set of animations to be started on the next animation frame - private static final ThreadLocal<ArrayList<ValueAnimator>> sPendingAnimations = - new ThreadLocal<ArrayList<ValueAnimator>>() { - @Override - protected ArrayList<ValueAnimator> initialValue() { - return new ArrayList<ValueAnimator>(); - } - }; - - /** - * Internal per-thread collections used to avoid set collisions as animations start and end - * while being processed. - */ - private static final ThreadLocal<ArrayList<ValueAnimator>> sDelayedAnims = - new ThreadLocal<ArrayList<ValueAnimator>>() { - @Override - protected ArrayList<ValueAnimator> initialValue() { - return new ArrayList<ValueAnimator>(); - } - }; - - private static final ThreadLocal<ArrayList<ValueAnimator>> sEndingAnims = - new ThreadLocal<ArrayList<ValueAnimator>>() { - @Override - protected ArrayList<ValueAnimator> initialValue() { - return new ArrayList<ValueAnimator>(); - } - }; - - private static final ThreadLocal<ArrayList<ValueAnimator>> sReadyAnims = - new ThreadLocal<ArrayList<ValueAnimator>>() { - @Override - protected ArrayList<ValueAnimator> initialValue() { - return new ArrayList<ValueAnimator>(); - } - }; - // The time interpolator to be used if none is set on the animation private static final TimeInterpolator sDefaultInterpolator = new AccelerateDecelerateInterpolator(); - // type evaluators for the primitive types handled by this implementation - private static final TypeEvaluator sIntEvaluator = new IntEvaluator(); - private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator(); - /** * Used to indicate whether the animation is currently playing in reverse. This causes the * elapsed fraction to be inverted to calculate the appropriate values. @@ -567,6 +512,20 @@ public class ValueAnimator extends Animator { * */ private static class AnimationHandler extends Handler { + // The per-thread list of all active animations + private final ArrayList<ValueAnimator> mAnimations = 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>(); + + /** + * Internal per-thread collections used to avoid set collisions as animations start and end + * while being processed. + */ + private final ArrayList<ValueAnimator> mDelayedAnims = new ArrayList<ValueAnimator>(); + private final ArrayList<ValueAnimator> mEndingAnims = new ArrayList<ValueAnimator>(); + private final ArrayList<ValueAnimator> mReadyAnims = new ArrayList<ValueAnimator>(); + /** * There are only two messages that we care about: ANIMATION_START and * ANIMATION_FRAME. The START message is sent when an animation's start() @@ -582,13 +541,13 @@ public class ValueAnimator extends Animator { @Override public void handleMessage(Message msg) { boolean callAgain = true; - ArrayList<ValueAnimator> animations = sAnimations.get(); - ArrayList<ValueAnimator> delayedAnims = sDelayedAnims.get(); + ArrayList<ValueAnimator> animations = mAnimations; + ArrayList<ValueAnimator> delayedAnims = mDelayedAnims; switch (msg.what) { // TODO: should we avoid sending frame message when starting if we // were already running? case ANIMATION_START: - ArrayList<ValueAnimator> pendingAnimations = sPendingAnimations.get(); + ArrayList<ValueAnimator> pendingAnimations = mPendingAnimations; if (animations.size() > 0 || delayedAnims.size() > 0) { callAgain = false; } @@ -606,7 +565,7 @@ public class ValueAnimator extends Animator { ValueAnimator anim = pendingCopy.get(i); // If the animation has a startDelay, place it on the delayed list if (anim.mStartDelay == 0) { - anim.startAnimation(); + anim.startAnimation(this); } else { delayedAnims.add(anim); } @@ -617,8 +576,8 @@ public class ValueAnimator extends Animator { // currentTime holds the common time for all animations processed // during this frame long currentTime = AnimationUtils.currentAnimationTimeMillis(); - ArrayList<ValueAnimator> readyAnims = sReadyAnims.get(); - ArrayList<ValueAnimator> endingAnims = sEndingAnims.get(); + ArrayList<ValueAnimator> readyAnims = mReadyAnims; + ArrayList<ValueAnimator> endingAnims = mEndingAnims; // First, process animations currently sitting on the delayed queue, adding // them to the active animations if they are ready @@ -633,7 +592,7 @@ public class ValueAnimator extends Animator { if (numReadyAnims > 0) { for (int i = 0; i < numReadyAnims; ++i) { ValueAnimator anim = readyAnims.get(i); - anim.startAnimation(); + anim.startAnimation(this); anim.mRunning = true; delayedAnims.remove(anim); } @@ -665,7 +624,7 @@ public class ValueAnimator extends Animator { } if (endingAnims.size() > 0) { for (i = 0; i < endingAnims.size(); ++i) { - endingAnims.get(i).endAnimation(); + endingAnims.get(i).endAnimation(this); } endingAnims.clear(); } @@ -921,7 +880,8 @@ public class ValueAnimator extends Animator { mPlayingState = STOPPED; mStarted = true; mStartedDelay = false; - sPendingAnimations.get().add(this); + AnimationHandler animationHandler = getOrCreateAnimationHandler(); + animationHandler.mPendingAnimations.add(this); if (mStartDelay == 0) { // This sets the initial value of the animation, prior to actually starting it running setCurrentPlayTime(getCurrentPlayTime()); @@ -937,11 +897,6 @@ public class ValueAnimator extends Animator { } } } - AnimationHandler animationHandler = sAnimationHandler.get(); - if (animationHandler == null) { - animationHandler = new AnimationHandler(); - sAnimationHandler.set(animationHandler); - } animationHandler.sendEmptyMessage(ANIMATION_START); } @@ -954,8 +909,10 @@ public class ValueAnimator extends Animator { public void cancel() { // Only cancel if the animation is actually running or has been started and is about // to run - if (mPlayingState != STOPPED || sPendingAnimations.get().contains(this) || - sDelayedAnims.get().contains(this)) { + AnimationHandler handler = getOrCreateAnimationHandler(); + if (mPlayingState != STOPPED + || handler.mPendingAnimations.contains(this) + || handler.mDelayedAnims.contains(this)) { // Only notify listeners if the animator has actually started if (mRunning && mListeners != null) { ArrayList<AnimatorListener> tmpListeners = @@ -964,16 +921,17 @@ public class ValueAnimator extends Animator { listener.onAnimationCancel(this); } } - endAnimation(); + endAnimation(handler); } } @Override public void end() { - if (!sAnimations.get().contains(this) && !sPendingAnimations.get().contains(this)) { + AnimationHandler handler = getOrCreateAnimationHandler(); + if (!handler.mAnimations.contains(this) && !handler.mPendingAnimations.contains(this)) { // Special case if the animation has not yet started; get it ready for ending mStartedDelay = false; - startAnimation(); + startAnimation(handler); } else if (!mInitialized) { initAnimation(); } @@ -984,7 +942,7 @@ public class ValueAnimator extends Animator { } else { animateValue(1f); } - endAnimation(); + endAnimation(handler); } @Override @@ -1020,10 +978,10 @@ public class ValueAnimator extends Animator { * Called internally to end an animation by removing it from the animations list. Must be * called on the UI thread. */ - private void endAnimation() { - sAnimations.get().remove(this); - sPendingAnimations.get().remove(this); - sDelayedAnims.get().remove(this); + private void endAnimation(AnimationHandler handler) { + handler.mAnimations.remove(this); + handler.mPendingAnimations.remove(this); + handler.mDelayedAnims.remove(this); mPlayingState = STOPPED; if (mRunning && mListeners != null) { ArrayList<AnimatorListener> tmpListeners = @@ -1041,9 +999,9 @@ public class ValueAnimator extends Animator { * Called internally to start an animation by adding it to the active animations list. Must be * called on the UI thread. */ - private void startAnimation() { + private void startAnimation(AnimationHandler handler) { initAnimation(); - sAnimations.get().add(this); + handler.mAnimations.add(this); if (mStartDelay > 0 && mListeners != null) { // Listeners were already notified in start() if startDelay is 0; this is // just for delayed animations @@ -1229,13 +1187,14 @@ public class ValueAnimator extends Animator { /** * Return the number of animations currently running. * - * Used by StrictMode internally to annotate violations. Only - * called on the main thread. + * Used by StrictMode internally to annotate violations. + * May be called on arbitrary threads! * * @hide */ public static int getCurrentAnimationsCount() { - return sAnimations.get().size(); + AnimationHandler handler = sAnimationHandler.get(); + return handler != null ? handler.mAnimations.size() : 0; } /** @@ -1245,9 +1204,21 @@ public class ValueAnimator extends Animator { * @hide */ public static void clearAllAnimations() { - sAnimations.get().clear(); - sPendingAnimations.get().clear(); - sDelayedAnims.get().clear(); + AnimationHandler handler = sAnimationHandler.get(); + if (handler != null) { + handler.mAnimations.clear(); + handler.mPendingAnimations.clear(); + handler.mDelayedAnims.clear(); + } + } + + private AnimationHandler getOrCreateAnimationHandler() { + AnimationHandler handler = sAnimationHandler.get(); + if (handler == null) { + handler = new AnimationHandler(); + sAnimationHandler.set(handler); + } + return handler; } @Override |