Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android動畫之原理篇(四)

Android動畫之原理篇(四)

編輯:關於Android編程

本文講述動畫的整個執行流程

在前面的文章中有講到,Android動畫的啟動方式如下:

ObjectAnimator anim = ObjectAnimator.ofFloat(targetObject, "alpha", 0f, 1f); //step 1
anim.setDuration(1000); //Step 2
anim.start();           //Step 3

那麼接下來,我們就從源碼中來分析,分析這3條語句是如何調起動畫的。所有代碼來源於Android sdk 22,為了精簡文章篇幅,部分源碼的方法只截了與動畫流程相關的關鍵代碼片段。


1. ofFloat()

step 1: ObjectAnimator.ofFloat,是一個靜態方法。首先創建ObjectAnimator對象,並指定target對象和屬性名。然後setFloatValues(values)方法,經幾次調用,最後調用KeyframeSet.ofFloat(values),創建了一個只有起始幀和結束幀(2-keyframe)的KeyframeSet對象。

public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
    //創建ObjectAnimator對象
    ObjectAnimator anim = new ObjectAnimator(target, propertyName);
    //設置float類型值
    anim.setFloatValues(values);
    return anim;
}

2. setDuration()

step 2: anim.setDuration(1000),用於設置動畫的執行總時間,調用父類ValueAnimator的方法:

public ValueAnimator setDuration(long duration) {
    if (duration < 0) {
        throw new IllegalArgumentException("Animators cannot have negative duration: " +
                duration);
    }
    //mUnscaledDuration的默認值為300ms
    mUnscaledDuration = duration;
    //更新duration
    updateScaledDuration();  //代碼見下方
    return this;
}

private void updateScaledDuration() {
    // sDurationScale默認為1
    mDuration = (long)(mUnscaledDuration * sDurationScale);
}

3. start()

step 3: anim.start(),啟動動畫,這整個動畫過程中最為復雜的流程。首先判斷是否存在活動或將要活動的,若存在則根據條件進行相應的取消操作。 其中AnimationHandler包含mAnimations(活動動畫), mPendingAnimations(下一幀的動畫),mDelayedAnims(延時動畫)這3個動畫ArrayList。

3-1 ObjectAnimator.start()

調用ObjectAnimator中start方法,開啟動畫的第一步:

public void start() {
    // 獲取AnimationHandler,並進行取消動畫操作
    AnimationHandler handler = sAnimationHandler.get();
    if (handler != null) {
        int numAnims = handler.mAnimations.size();
        for (int i = numAnims - 1; i >= 0; i--) {
            if (handler.mAnimations.get(i) instanceof ObjectAnimator) {
                ObjectAnimator anim = (ObjectAnimator) handler.mAnimations.get(i);
                if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
                    anim.cancel();
                }
            }
        }
        numAnims = handler.mPendingAnimations.size();
        for (int i = numAnims - 1; i >= 0; i--) {
            if (handler.mPendingAnimations.get(i) instanceof ObjectAnimator) {
                ObjectAnimator anim = (ObjectAnimator) handler.mPendingAnimations.get(i);
                if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
                    anim.cancel();
                }
            }
        }
        numAnims = handler.mDelayedAnims.size();
        for (int i = numAnims - 1; i >= 0; i--) {
            if (handler.mDelayedAnims.get(i) instanceof ObjectAnimator) {
                ObjectAnimator anim = (ObjectAnimator) handler.mDelayedAnims.get(i);
                if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
                    anim.cancel();
                }
            }
        }
    }
    //調用父類方法
    super.start(); //代碼見(3-2)
}

3-2 ValueAnimator.start()

進入ValueAnimator對象的方法。調用start(),再跳轉到start(false),為了精簡內容,下面方法只截取關鍵的代碼片段:

private void start(boolean playBackwards) {
    ...

    int prevPlayingState = mPlayingState;
    mPlayingState = STOPPED;
    // 更新時間duration
    updateScaledDuration();

    //獲取或創建AnimationHandler,
    //AnimationHandler的核心功能是靠Choreographer完成,後面會詳細介紹Choreographer;
    AnimationHandler animationHandler = getOrCreateAnimationHandler();

    // 將當前動畫添加到下一幀動畫列表中
    animationHandler.mPendingAnimations.add(this);

    if (mStartDelay == 0) {
        //初始化動畫參數
        if (prevPlayingState != SEEKED) {
            setCurrentPlayTime(0);  //代碼見(3-2-1)
        }
        mPlayingState = STOPPED;
        mRunning = true;
        notifyStartListeners(); //代碼見(3-2-2)
    }
    animationHandler.start();   //代碼見(3-2-3)
}

(3-2-1) 其中setCurrentPlayTime(0),多次跳轉後,調用animateValue(1),插值器默認為AccelerateDecelerateInterpolator。此處首次調用onAnimationUpdate方法,

動畫更新,通過實現AnimatorUpdateListener接口的onAnimationUpdate()方法。

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); //更新動畫狀態
        }
    }
}

(3-2-2) 其中notifyStartListeners(),主要功能是調用onAnimationStart(this),動畫啟動:

通知動畫開始,通過實現AnimatorListener接口的onAnimationStart()方法。

private void notifyStartListeners() {
    if (mListeners != null && !mStartListenersCalled) {
        ArrayList<AnimatorListener> tmpListeners =
                (ArrayList<AnimatorListener>) mListeners.clone();
        int numListeners = tmpListeners.size();
        for (int i = 0; i < numListeners; ++i) {
            tmpListeners.get(i).onAnimationStart(this); //動畫開始
        }
    }
    mStartListenersCalled = true;
}

從此處開始,將是循環執行的開始

(3-2-3) 其中animationHandler.start(),交給mChoreographer來執行動畫。

private void scheduleAnimation() {
    if (!mAnimationScheduled) {
        mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null); //代碼見(3-3)
        mAnimationScheduled = true;
    }
}

3-3 Choreographer

進入Choreographer類,這是動畫最為核心的一個類,動畫最後都會走到這個類裡面。mChoreographer.postCallback 方法,經幾次調用,最後調用postCallbackDelayedInternal(),傳入進去的action的animationHandler

private void postCallbackDelayedInternal(int callbackType,
        Object action, Object token, long delayMillis) {
    ...

    synchronized (mLock) {
        final long now = SystemClock.uptimeMillis();
        final long dueTime = now + delayMillis;
         //此處action 為 animationHandler,添加到Callback隊列
        mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

        if (dueTime <= now) {
             //傳進來的delayMillis=0,故進入才分支
            scheduleFrameLocked(now);    //代碼見(3-3-1)
        } else {
            Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
            msg.arg1 = callbackType;
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, dueTime);
        }
    }
}

(3-3-1)scheduleFrameLocked(now),其中USE_VSYNC = SystemProperties.getBoolean("debug.choreographer.vsync", true),該屬性值一般都是缺省的,則USE_VSYNC =true,啟動VSYNC垂直同步信號方式來觸發動畫。當fps=60時,則1/60 s≈16.7ms,故VSYNC信號上報的周期為16.7ms:

private void scheduleFrameLocked(long now) {
    if (!mFrameScheduled) {
        mFrameScheduled = true;
        if (USE_VSYNC) {
            if (DEBUG) {
                Log.d(TAG, "Scheduling next frame on vsync.");
            }

            // 正運行在Looper線程
            if (isRunningOnLooperThreadLocked()) {
                scheduleVsyncLocked();  //代碼見(3-3-2)
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
                msg.setAsynchronous(true);
                mHandler.sendMessageAtFrontOfQueue(msg);
            }
        } else {
            final long nextFrameTime = Math.max(
                    mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
            if (DEBUG) {
                Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
            }
            Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, nextFrameTime);
        }
    }
}

(3-3-2)scheduleVsyncLocked()再調用DisplayEventReceiverDisplayEventReceiver實現了Runnable接口,繼承DisplayEventReceiver,提供了一種能接收display event,比如垂直同步的機制,通過Looper不斷掃描信息,直到收到VSYNC信號,觸發相應操作。

private void scheduleVsyncLocked() {
    mDisplayEventReceiver.scheduleVsync();
}

(3-3-3)當接收到vsync信號時,會調用onVsync()方法,通過sendMessageAtTime,交由FrameHandler來處理消息事件

    @Override
    public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
        ...

        long now = System.nanoTime();
        if (timestampNanos > now) {
            Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
                    + " ms in the future!  Check that graphics HAL is generating vsync "
                    + "timestamps using the correct timebase.");
            timestampNanos = now;
        }

        if (mHavePendingVsync) {
            Log.w(TAG, "Already have a pending vsync event.  There should only be "
                    + "one at a time.");
        } else {
            mHavePendingVsync = true;
        }

        mTimestampNanos = timestampNanos;
        mFrame = frame;
        Message msg = Message.obtain(mHandler, this);
        msg.setAsynchronous(true);
        mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
    }

(3-3-4) FrameHandler在收到信息時,進行doFrame(System.nanoTime(), 0),該方法重點最下面的三行doCallbacks語句,分別是CALLBACK_INPUTCALLBACK_ANIMATIONCALLBACK_TRAVERSAL,可看出回調的處理順序依次為:input事件, 動畫,view布局和繪制。

void doFrame(long frameTimeNanos, int frame) {
    final long startNanos;
    synchronized (mLock) {
        if (!mFrameScheduled) {
            return; // no work to do
        }

        startNanos = System.nanoTime();
        final long jitterNanos = startNanos - frameTimeNanos;

        //mFrameIntervalNanos 代表兩幀之間的刷新時間
        if (jitterNanos >= mFrameIntervalNanos) {
            final long skippedFrames = jitterNanos / mFrameIntervalNanos;
            // 說明已經掉幀了
            if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
                Log.i(TAG, "Skipped " + skippedFrames + " frames!  "
                        + "The application may be doing too much work on its main thread.");
            }
            final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
            frameTimeNanos = startNanos - lastFrameOffset;
        }

        if (frameTimeNanos < mLastFrameTimeNanos) {
            if (DEBUG) {
                Log.d(TAG, "Frame time appears to be going backwards.  May be due to a "
                        + "previously skipped frame.  Waiting for next vsync.");
            }
            scheduleVsyncLocked();
            return;
        }

        mFrameScheduled = false;
        mLastFrameTimeNanos = frameTimeNanos;
    }

    doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);      //代碼見(3-3-5)
    doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);  //代碼見(3-3-5)
    doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);  //代碼見(3-3-5)

}

(3-3-5) doCallbacks,遍歷執行所有的run方法,再回收相應的Callback:

void doCallbacks(int callbackType, long frameTimeNanos) {
    CallbackRecord callbacks;
    synchronized (mLock) {
        final long now = SystemClock.uptimeMillis();
        callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now);
        if (callbacks == null) {
            return;
        }
        mCallbacksRunning = true;
    }
    try {
        for (CallbackRecord c = callbacks; c != null; c = c.next) {
            if (DEBUG) {
                Log.d(TAG, "RunCallback: type=" + callbackType
                        + ", action=" + c.action + ", token=" + c.token
                        + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
            }
            //此處調用的實際上是animationHandler.run()
            c.run(frameTimeNanos);  //代碼見(3-4-2)
        }
    } finally {
        synchronized (mLock) {
            mCallbacksRunning = false;
            do {
                final CallbackRecord next = callbacks.next;
                recycleCallbackLocked(callbacks);  //回收Callback
                callbacks = next;
            } while (callbacks != null);
        }
    }
}

3-4 animationHandler.run()

該方法是由Choreographer調用的

@Override
public void run() {
    mAnimationScheduled = false;
    //具體實現動畫的一陣內容
    doAnimationFrame(mChoreographer.getFrameTime());   //代碼見(3-4-1)
}

(3-4-1)doAnimationFrame是消耗幀的過程,其中startAnimation會初始化Evalutor.

 private void doAnimationFrame(long frameTime) {
    // 清空mPendingAnimations
    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 (anim.mStartDelay == 0) {
                anim.startAnimation(this); // 將mPendingAnimations動畫添加到活動動畫list
            } else {
                mDelayedAnims.add(anim); // 如果有delay時間的,就添加到 mDelayedAnims
            }
        }
    }

    // 將已經到時的延時動畫,加入到mReadyAnims
    int numDelayedAnims = mDelayedAnims.size();
    for (int i = 0; i < numDelayedAnims; ++i) {
        ValueAnimator anim = mDelayedAnims.get(i);
        if (anim.delayedAnimationFrame(frameTime)) {
            mReadyAnims.add(anim);
        }
    }
    //移除mDelayedAnims動畫,並清空mReadyAnims動畫
    int numReadyAnims = mReadyAnims.size();
    if (numReadyAnims > 0) {
        for (int i = 0; i < numReadyAnims; ++i) {
            ValueAnimator anim = mReadyAnims.get(i);
            anim.startAnimation(this);   //將mReadyAnims動畫添加到活動動畫list
            anim.mRunning = true;
            mDelayedAnims.remove(anim);
        }
        mReadyAnims.clear();
    }

    // 處理所有的活動動畫,根據返回值決定是否將相應的動畫添加到endAnims.
    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)) { //代碼見(3-4-2)
            mEndingAnims.add(anim);
        }
    }
    //清空mTmpAnimations 和 mEndingAnims
    mTmpAnimations.clear();
    if (mEndingAnims.size() > 0) {
        for (int i = 0; i < mEndingAnims.size(); ++i) {
            // 動畫結束
            mEndingAnims.get(i).endAnimation(this);  //代碼見(3-4-4)
        }
        mEndingAnims.clear();
    }

    // 活動或延時動畫不會空時,調用scheduleAnimation
    if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) {
        scheduleAnimation();   //代碼見(3-4-5)
    }
}

(3-4-2) animationFrame 繪制動畫的幀,當動畫的elapsed time時間超過動畫duration時,動畫將結束。

boolean animationFrame(long currentTime) {
    boolean done = false;
    switch (mPlayingState) {
    case RUNNING:
    case SEEKED:
        float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f;
        if (mDuration == 0 && mRepeatCount != INFINITE) {
            // Skip to the end
            mCurrentIteration = mRepeatCount;
            if (!mReversing) {
                mPlayingBackwards = false;
            }
        }
        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);   //代碼見(3-4-3)
        break;
    }

    return done;
}

(3-4-3)animateValue(fraction),動畫的每一幀變化,都會調用這個方式,將 elapsed fraction通過Interpolation轉換為所需的插值。之後獲取的動畫屬性值,對於evaluator,大多數情況是在動畫更新方式中調用,用。

動畫更新,通過實現AnimatorUpdateListener接口的onAnimationUpdate()方法。

 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); //更新動畫
        }
    }
}

(3-4-4)endAnimation()

protected void endAnimation(AnimationHandler handler) {
    handler.mAnimations.remove(this);
    handler.mPendingAnimations.remove(this);
    handler.mDelayedAnims.remove(this);
    mPlayingState = STOPPED;
    mPaused = false;
    if ((mStarted || mRunning) && mListeners != null) {
        if (!mRunning) {
            // If it's not yet running, then start listeners weren't called. Call them now.
            notifyStartListeners();
         }
        ArrayList<AnimatorListener> tmpListeners =
                (ArrayList<AnimatorListener>) mListeners.clone();
        int numListeners = tmpListeners.size();
        for (int i = 0; i < numListeners; ++i) {
            tmpListeners.get(i).onAnimationEnd(this); // 動畫結束
        }
    }
    mRunning = false;
    mStarted = false;
    mStartListenersCalled = false;
    mPlayingBackwards = false;
    mReversing = false;
    mCurrentIteration = 0;
    if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
        Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, getNameForTrace(),
                System.identityHashCode(this));
    }
}

動畫結束,通過實現AnimatorListener接口的onAnimationEnd()方法。

(3-4-5)scheduleAnimation再次調用mChoreographer,與(3-2-3)步驟構成循環流程,不斷重復執行這個過程,直到動畫結束

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

到此,整個動畫的完成流程已全部疏通完畢。


總結

動畫主線流程: ObjectAnimator.start() -> ValueAnimator.start() -> animationHandler.start() -> AnimationHandler.scheduleAnimation() -> Choreographer.postCallback() -> postCallbackDelayed() -> postCallbackDelayedInternal() -> scheduleFrameLocked() -> scheduleVsyncLocked() -> DisplayEventReceiver.scheduleVsync() -> onVsync() -> doFrame()-> doCallbacks() -> animationHandler.run() ->doAnimationFrame() -> animationFrame() -> animateValue() 目前先文字敘述,後面有空再畫詳細流程圖。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved