注意Animator并没有自己的thread, 而是使用start 它的thread, 只是有一个自己的可以向该thread post 的 handler罢了
     * The animation started by calling this method will be run on the thread that called
     * this method. This thread should have a Looper on it. Also, if the animation will animate
     * properties of objects in the view hierarchy, then the calling thread should be the UI
     * thread for that view hierarchy

private void start(boolean playBackwards) {
    if (Looper.myLooper() == null) {
        throw new AndroidRuntimeException("Animators may only be run on Looper threads");
    }
    mPlayingBackwards = playBackwards;
    mCurrentIteration = 0;
    mPlayingState = STOPPED;
    mStarted = true;
    mStartedDelay = false;
    mPaused = false;
    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(0);
        mPlayingState = STOPPED;
        mRunning = true;
        notifyStartListeners();
    }
    animationHandler.start();
}


private static AnimationHandler getOrCreateAnimationHandler() {
    AnimationHandler handler = sAnimationHandler.get();
    if (handler == null) {
        handler = new AnimationHandler();
        sAnimationHandler.set(handler);
    }
    return handler;
}

 
protected static ThreadLocal<AnimationHandler> sAnimationHandler =
        new ThreadLocal<AnimationHandler>();

protected static class AnimationHandler implements Runnable {
    ..................................
    private AnimationHandler() {
        mChoreographer = Choreographer.getInstance();
    }

    ..................................
    public void start() {
        scheduleAnimation();
    }

    ..................................
    private void scheduleAnimation() {
        if (!mAnimationScheduled) {
            mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
            mAnimationScheduled = true;
        }
    }

    .................................
    // Called by the Choreographer.
    @Override
    public void run() {
        mAnimationScheduled = false;
        doAnimationFrame(mChoreographer.getFrameTime());
    }

    .................................
    private void doAnimationFrame(long frameTime) {
        // mPendingAnimations holds any animations that have requested to be started
        // We're going to clear mPendingAnimations, but starting animation may
        // cause more to be added to the pending list (for example, if one animation
        // starting triggers another starting). So we loop until mPendingAnimations
        // is empty.
        while (mPendingAnimations.size() > 0) {
            ArrayList<ValueAnimator> pendingCopy =
                    (ArrayList<ValueAnimator>) mPendingAnimations.clone();
            mPendingAnimations.clear();
            int count = pendingCopy.size();
            for (int i = 0; i < count; ++i) {
                ValueAnimator anim = pendingCopy.get(i);
                // If the animation has a startDelay, place it on the delayed list
                if (anim.mStartDelay == 0) {
                    anim.startAnimation(this);
                } else {
                    mDelayedAnims.add(anim);
                }
            }
        }
        ........................................................
        int numAnims = mAnimations.size();
            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.isEmpty() || !mDelayedAnims.isEmpty()) {
            scheduleAnimation();
        }
    }
}

...............................................................
private void startAnimation(AnimationHandler handler) {
    if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
        Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, getNameForTrace(),
                System.identityHashCode(this));
    }
    initAnimation();
    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
        notifyStartListeners();
    }
}

/**
 * Processes a frame of the animation, adjusting the start time if needed.
 *
 * @param frameTime The frame time.
 * @return true if the animation has ended.
 */
final boolean doAnimationFrame(long frameTime) {
    if (mPlayingState == STOPPED) {
        mPlayingState = RUNNING;
        if (mSeekTime < 0) {
            mStartTime = frameTime;
        } else {
            mStartTime = frameTime - mSeekTime;
            // Now that we're playing, reset the seek time
            mSeekTime = -1;
        }
    }
    if (mPaused) {
        if (mPauseTime < 0) {
            mPauseTime = frameTime;
        }
        return false;
    } else if (mResumed) {
        mResumed = false;
        if (mPauseTime > 0) {
            // Offset by the duration that the animation was paused
            mStartTime += (frameTime - mPauseTime);
        }
    }
    // The frame time might be before the start time during the first frame of
    // an animation.  The "current time" must always be on or after the start
    // time to avoid animating frames at negative time intervals.  In practice, this
    // is very rare and only happens when seeking backwards.
    final long currentTime = Math.max(frameTime, mStartTime);
    return animationFrame(currentTime);
}


/**
 * This internal function processes a single animation frame for a given animation. The
 * currentTime parameter is the timing pulse sent by the handler, used to calculate the
 * elapsed duration, and therefore
 * the elapsed fraction, of the animation. The return value indicates whether the animation
 * should be ended (which happens when the elapsed time of the animation exceeds the
 * animation's duration, including the repeatCount).
 *
 * @param currentTime The current time, as tracked by the static timing handler
 * @return true if the animation's duration, including any repetitions due to
 * <code>repeatCount</code>, has been exceeded and the animation should be ended.
 */
boolean animationFrame(long currentTime) {
    boolean done = false;
    switch (mPlayingState) {
    case RUNNING:
    case SEEKED:
        float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f;
        if (fraction >= 1f) {
            if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) {
                // Time to repeat
                if (mListeners != null) {
                    int numListeners = mListeners.size();
                    for (int i = 0; i < numListeners; ++i) {
                        mListeners.get(i).onAnimationRepeat(this);
                    }
                }
                if (mRepeatMode == REVERSE) {
                    mPlayingBackwards = !mPlayingBackwards;
                }
                mCurrentIteration += (int)fraction;
                fraction = fraction % 1f;
                mStartTime += mDuration;
            } else {
                done = true;
                fraction = Math.min(fraction, 1.0f);
            }
        }
        if (mPlayingBackwards) {
            fraction = 1f - fraction;
        }
        animateValue(fraction);
        break;
    }

    return done;
}


/**
 * This method is called with the elapsed fraction of the animation during every
 * animation frame. This function turns the elapsed fraction into an interpolated fraction
 * and then into an animated value (from the evaluator. The function is called mostly during
 * animation updates, but it is also called when the <code>end()</code>
 * function is called, to set the final value on the property.
 *
 * <p>Overrides of this method must call the superclass to perform the calculation
 * of the animated value.</p>
 *
 * @param fraction The elapsed fraction of the animation.
 */
void animateValue(float fraction) {
    fraction = mInterpolator.getInterpolation(fraction);
    mCurrentFraction = fraction;
    int numValues = mValues.length;
    for (int i = 0; i < numValues; ++i) {
        mValues[i].calculateValue(fraction);
    }
    if (mUpdateListeners != null) {
        int numListeners = mUpdateListeners.size();
        for (int i = 0; i < numListeners; ++i) {
            mUpdateListeners.get(i).onAnimationUpdate(this);
        }
    }
}




1.ValueAnimator->start():


取得一个ThreadLocal的Runnable(animationHandler),里面封存了一些关于本animator的信息,然后animationHandler.start()


2.AnimationHandler->start()->scheduleAnimation()->mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null):

<这里的CALLBACK_ANIMATION TASK, 其优先级在Choreographer中低于CALLBACK_INPUT, 高于CALLBACK_TRAVERSAL,所以可以认为对于android的每一帧

动画是被优先运行的,动画全部处理完了以后,才会轮到measure layout draw>

将自己schedule给Choreographer,让Choreographer在合适的时机回调自己。(注意,Choreographer的回调是跑在UI-thread)


3.被运行起来时: AnimationHandler->doAnimationFrame(mChoreographer.getFrameTime())


->anim.startAnimation(this)首先把还没有真正start的animator start一边,调用其start回调 

 ->对于已经在run的animator: anim.doAnimationFrame(frameTime), 这个函数里就是一系列的调整值,并调用相应的update回调。 

 -> 

 if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) {


    scheduleAnimation();


} 如果还有没有run完的animator,那么就继续将自己schedule给Choreographer,等待下一次的回调.


顺便看了下Aniamtion的原理,Animation和Animator不同,Animation通过在View的draw()中调用了drawAnimation()来实现效果.

有一点注意:

2.x系列不支持Animator,因为这是后来才引入的,不过可以用nineoldandroids这个库来模拟实现,原理差不过,只不过2.x没有Choreographer,因此调度时会有差别.