編輯:關於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,為了精簡文章篇幅,部分源碼的方法只截了與動畫流程相關的關鍵代碼片段。
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;
}
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);
}
step 3: anim.start(),啟動動畫,這整個動畫過程中最為復雜的流程。首先判斷是否存在活動或將要活動的,若存在則根據條件進行相應的取消操作。 其中AnimationHandler包含mAnimations(活動動畫), mPendingAnimations(下一幀的動畫),mDelayedAnims(延時動畫)這3個動畫ArrayList。
調用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)
}
進入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;
}
}
進入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()再調用DisplayEventReceiver
。DisplayEventReceiver
實現了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_INPUT
,CALLBACK_ANIMATION
,CALLBACK_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);
}
}
}
該方法是由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() 目前先文字敘述,後面有空再畫詳細流程圖。
打開項目以後,點擊項目,選擇 Build 菜單, 然後選擇 Generate Signed APK. 如下圖所示:打開生成對話框:選擇 Create new... 按鈕,
雙清,也稱為雙wipe,是Android系統刷機專屬名詞,wipe因為解釋為:擦,拭;擦去,抹去的意思,所以雙清也是「恢復出廠設置」和「清除緩存」,由於在英
原因:編譯器版本的問題。Java 1.5的編譯器默認對父類的方法進行覆蓋,采用@Override進行說明;但1.6已經擴展到對接口的方法;所以如果還是以Java 1.5
本文實例為大家分享了Android控件ImageSwitcher實現引導界面的代碼,供大家參考,具體內容如下效果圖:布局代碼:<?xml version=1