屬性動畫源碼分析-start方法

屬性動畫的啟動我們是通過如下來完成的:

  objectAnimator.start();//動畫開始時從start方法開始的

start()核心代碼如下:

AnimationHandler.getInstance().autoCancelBasedOn(this);
super.start();

start()方法主要做了兩件事,一個是檢測如果動畫已經(jīng)執(zhí)行,則停止動畫;另一方面調(diào)用了父類的start()方法。

ObjectAnimator的父類是ValueAnimator,它的start()方法如下:

start(false);

我們接著看下ValueAnimator的這個方法,核心代碼如下:

//開啟動畫的線程要有Looper對象=》動畫只能在主線程中運行
if (Looper.myLooper() == null) {
   throw new AndroidRuntimeException("Animators may only be run on Looper threads");
}
addAnimationCallback(0);
if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) {
   startAnimation(); //如果沒有啟動延遲,就立即啟動動畫   
   if (mSeekFraction == -1) {  
       setCurrentPlayTime(0);
   } else {
       setCurrentFraction(mSeekFraction);
   }
}

這里主要看addAnimationCallback(0);

    private void addAnimationCallback(long delay) {
        if (!mSelfPulse) {
            return;
        }
        //添加一個AnimationFrameCallback,ValueAnimator實現(xiàn)了AnimationFrameCallback接口
        getAnimationHandler().addAnimationFrameCallback(this, delay);
    }

流程走到這里,需要看兩個方法:

  • getAnimationHandler()
    看下getAnimationHandler()這個方法:
 public AnimationHandler getAnimationHandler() {
        return AnimationHandler.getInstance();//getInstance()這個方法
}

AnimationHandler不是Handler,而是AnimationHandler用ThreadLocal保證每個線程只有一個實例。做到線程中單例,“getInstance()”方法以及實現(xiàn)如下:

public final static ThreadLocal<AnimationHandler> sAnimatorHandler = new ThreadLocal<>();
private boolean mListDirty = false;

public static AnimationHandler getInstance() {
   if (sAnimatorHandler.get() == null) {
      sAnimatorHandler.set(new AnimationHandler());
   }
   return sAnimatorHandler.get();
}
  • addAnimationFrameCallback
    addAnimationFrameCallback的核心代碼:
public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
  if (mAnimationCallbacks.size() == 0) {
     getProvider().postFrameCallback(mFrameCallback);
  }
}

AnimationFrameCallbackValueAnimator的父類,getProvider()返回的是MyFrameCallbackProvider,我們來看下postFrameCallback這個方法,通過不斷的調(diào)用跳轉(zhuǎn),我們來到了ChoreographerpostCallbackDelayedInternal這個方法:

private void postCallbackDelayedInternal(int callbackType,
    Object action, Object token, long delayMillis) {//這個action就是callback

   synchronized (mLock) {
      final long now = SystemClock.uptimeMillis();
      final long dueTime = now + delayMillis;
      mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
      if (dueTime <= now) {
         //沒有延遲,直接開始調(diào)度
         scheduleFrameLocked(now);
      } else {
         //有延遲,就通過handler延時發(fā)送一個message
         Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
         msg.arg1 = callbackType;
         msg.setAsynchronous(true);
         mHandler.sendMessageAtTime(msg, dueTime);
      }
    }
}

看下scheduleFrameLocked(now);這個方法:,核心代碼如下:

if (USE_VSYNC) {//為動畫和繪圖啟動/禁用垂直同步信號
   //如果是在主線程就直接調(diào)度,否則就發(fā)送一個消息到主線程
   if (isRunningOnLooperThreadLocked()) {
       scheduleVsyncLocked();
   } else {
       Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
       msg.setAsynchronous(true);
       mHandler.sendMessageAtFrontOfQueue(msg);
   }      
} 

然后看下這個方法scheduleVsyncLocked,通過不斷的跳轉(zhuǎn),我們可以看到在DisplayEventReceiver這個類中的scheduleVsync方法如下:

public void scheduleVsync() {
   if (mReceiverPtr == 0) {
       Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "
                    + "receiver has already been disposed.");
   } else {
       nativeScheduleVsync(mReceiverPtr);
   }
}

nativeScheduleVsync方法其實是一個native方法,這個方法其實是向native層注冊成為觀察者,用來接收屏幕刷新信號。

private static native void nativeScheduleVsync(long receiverPtr);

總結(jié):start方法中檢測如果動畫已經(jīng)執(zhí)行,則停止動畫,并且限定了動畫只能在主線程中運行,動畫如果在主線程中運行,那么將會判斷有沒有啟動延遲,如果沒有就立即執(zhí)行動畫,通過AnimationHandlerThreadLocal保證每個線程只有一個實例。做到線程中單例。執(zhí)行動畫后,會為動畫和繪圖啟動垂直同步信號,通過向native曾注冊成為觀察者,用來接收屏幕刷新信號。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 【Android 動畫】 動畫分類補間動畫(Tween動畫)幀動畫(Frame 動畫)屬性動畫(Property ...
    Rtia閱讀 6,437評論 1 38
  • ??本文將對屬性動畫執(zhí)行流程做初步解析,由于屬性動畫是一套比較復(fù)雜的系統(tǒng),無法面面俱到,僅做基本流程解析先看一下基...
    亂世白衣閱讀 1,720評論 1 5
  • 寫的非常好,強烈推薦給大家 轉(zhuǎn)載請注明出處:http://blog.csdn.net/guolin_blog/ar...
    天天大保建閱讀 894評論 0 1
  • * 本篇文章已授權(quán)微信公眾號 guolin_blog (郭霖)獨家發(fā)布 屬性動畫有兩個比較重要的動畫執(zhí)行類 其中 ...
    看我眼前007閱讀 5,250評論 13 22
  • 這是關(guān)于一段旅途的回憶 一直都有個強烈而執(zhí)著的想法,要在20歲之前做件大事。 排除了種種不切實際的想法 我選擇了獨...
    May_a878閱讀 163評論 0 1

友情鏈接更多精彩內(nèi)容