美文网首页
分析Android属性动画源码的执行过程

分析Android属性动画源码的执行过程

作者: VegetableAD | 来源:发表于2016-11-24 17:52 被阅读555次

    我们从启动动画为着手点分析属性动画的执行过程

    @Override
    public void start() {    
      AnimationHandler.getInstance().autoCancelBasedOn(this);    
      if (DBG) {        
        Log.d(LOG_TAG, "Anim target, duration: " + getTarget() + ", " + getDuration());        
        for (int i = 0; i < mValues.length; ++i) {            
          PropertyValuesHolder pvh = mValues[i];            
          Log.d(LOG_TAG, "Values[" + i + "]: " + pvh.getPropertyName() + ", " + pvh.mKeyframes.getValue(0) + ", " + pvh.mKeyframes.getValue(1));        
        }    
      }    
      super.start();
    }
    

    该段代码只需看第一行和最后一行,第一行代码为查看ThreadLocal中是否有AnimationHandler实例,并为其赋初值,如果mAnimationCallbacks这个ArrayList中有保存回调,那么遍历该ArrayList并查看元素是否应该自动取消,最后一行调用了父类的start方法,那么我们就查看下ValueAnimator中的start方法

    @Overridepublic void start() {    
      start(false);
    }
    
    private void start(boolean playBackwards) {
      if (Looper.myLooper() == null) {        
          throw new AndroidRuntimeException("Animators may only be run on Looper threads");    
      }    
      mReversing = playBackwards;    
      // Special case: reversing from seek-to-0 should act as if not seeked at all.    
      if (playBackwards && mSeekFraction != -1 && mSeekFraction != 0) {
          if (mRepeatCount == INFINITE) {            
              // Calculate the fraction of the current iteration.            
              float fraction = (float) (mSeekFraction - Math.floor(mSeekFraction));
              mSeekFraction = 1 - fraction;        
          } else {
              mSeekFraction = 1 + mRepeatCount - mSeekFraction;
          }    
      }    
      mStarted = true;    
      mPaused = false;    
      mRunning = false;    
      // Resets mLastFrameTime when start() is called, so that if the animation was running,    
      // calling start() would put the animation in the    
      // started-but-not-yet-reached-the-first-frame phase.    
      mLastFrameTime = 0;    
      AnimationHandler animationHandler = AnimationHandler.getInstance();
      animationHandler.addAnimationFrameCallback(this, (long) (mStartDelay * sDurationScale));    
      if (mStartDelay == 0 || mSeekFraction >= 0) {        
        // If there's no start delay, init the animation and notify start listeners right away        
          // to be consistent with the previous behavior. Otherwise, postpone this until the first        
          // frame after the start delay.        
          startAnimation();        
          if (mSeekFraction == -1) {            
          // No seek, start at play time 0. Note that the reason we are not using fraction 0            
          // is because for animations with 0 duration, we want to be consistent with pre-N           
          // behavior: skip to the final value immediately.            
            setCurrentPlayTime(0);        
          } else {            
              setCurrentFraction(mSeekFraction);        
          }    
      }
    }
    

    可以看出动画时运行在有Looper中的线程中的(为什么要在Looper中因为之后的代码使用到了Handler),我们看到
    animationHandler.addAnimationFrameCallback(this, (long) (mStartDelay * sDurationScale));让我们走进这行代码深究一下

    public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {    
        if (mAnimationCallbacks.size() == 0) {
            getProvider().postFrameCallback(mFrameCallback);    
        }    
        if (!mAnimationCallbacks.contains(callback)) {
            mAnimationCallbacks.add(callback);    
        }    
        if (delay > 0) {        
            mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));    
        }
    }
    
    getProvider()返回的是MyFrameCallbackProvider的实例,而MyFrameCallbackProvider由实现了AnimationFrameCallbackProvider接口,所以让我们愉快的查看MyFrameCallbackProvider中的postFrameCallback方法
    @Overridepublic void postFrameCallback(Choreographer.FrameCallback callback) {  
        mChoreographer.postFrameCallback(callback);
    }
    

    该方法内部逐层调用最终调用了

    private void postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis) {    
        if (DEBUG_FRAMES) {        
            Log.d(TAG, "PostCallback: type=" + callbackType + ", action=" + action + ", token=" + token + ", delayMillis=" + delayMillis);    
        }    
        synchronized (mLock) {        
            final long now = SystemClock.uptimeMillis();        
            final long dueTime = now + delayMillis;
            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);       
            if (dueTime <= now) {           
               scheduleFrameLocked(now);       
            } else {           
               Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);         
               msg.arg1 = callbackType;   
               msg.setAsynchronous(true); 
               mHandler.sendMessageAtTime(msg, dueTime);    
            }  
        }
    }
    

    我们看到这里使用到了Handler,所以这就解释了为什么前面需要检查Looper是否为空了。我们可以看到逻辑是如果有延迟那么就运行else方法,没有设置延迟都是调用scheduleFrameLocked方法

    private void scheduleFrameLocked(long now) {    
       if (!mFrameScheduled) {        
          mFrameScheduled = true;        
          if (USE_VSYNC) {            
              if (DEBUG_FRAMES) {                
                  Log.d(TAG, "Scheduling next frame on vsync.");           
              }           
              // If running on the Looper thread, then schedule the vsync immediately,
             // otherwise post a message to schedule the vsync from the UI thread
            // as soon as possible.
              if (isRunningOnLooperThreadLocked()) {
                  scheduleVsyncLocked();
              } 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_FRAMES) {
                  Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
              }
              Message msg = mHandler.obtainMessage(MSG_DO_FRAME);            
              msg.setAsynchronous(true);
              mHandler.sendMessageAtTime(msg, nextFrameTime);
          }
       }
    }
    

    我们看出最后运行的是scheduleVsyncLocked();方法,而该方法内部调用的是native方法。因为之前调用传递的是Choreographer.FrameCallback实例,所以最终因该会调用该实例的doFrame方法,而会调用AnimationHandler的doAnimationFrame方法,而该方法又会调用ValueAnimator的doAnimationFrame方法

    public final void doAnimationFrame(long frameTime) {
        AnimationHandler handler = AnimationHandler.getInstance();
        if (mLastFrameTime == 0) {
            // First frame
            handler.addOneShotCommitCallback(this);
            if (mStartDelay > 0) {
                startAnimation();
            }
            if (mSeekFraction < 0) {
                mStartTime = frameTime;
            } else {
                long seekTime = (long) (getScaledDuration() * mSeekFraction);            mStartTime = frameTime - seekTime;
                mSeekFraction = -1;
            }
            mStartTimeCommitted = false; // allow start time to be compensated for jank
        }
        mLastFrameTime = frameTime;
        if (mPaused) {
            mPauseTime = frameTime;
            handler.removeCallback(this);
            return;
        } else if (mResumed) {
            mResumed = false;
            if (mPauseTime > 0) {
                // Offset by the duration that the animation was paused
                mStartTime += (frameTime - mPauseTime);
                mStartTimeCommitted = false; // allow start time to be compensated for jank
            }
            handler.addOneShotCommitCallback(this);
        }
        // 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);
        boolean finished = animateBasedOnTime(currentTime);
        if (finished) {
            endAnimation();
        }
    }
    

    我们看到从animateBasedOnTime(currentTime);方法的返回值用于判断是否结束动画

    boolean animateBasedOnTime(long currentTime) {
        boolean done = false;
        if (mRunning) {
            final long scaledDuration = getScaledDuration();
            final float fraction = scaledDuration > 0 ? (float)(currentTime - mStartTime) / scaledDuration : 1f;
            final float lastFraction = mOverallFraction;
            final boolean newIteration = (int) fraction > (int) lastFraction;
            final boolean lastIterationFinished = (fraction >= mRepeatCount + 1) && (mRepeatCount != INFINITE);
            if (scaledDuration == 0) {
                // 0 duration animator, ignore the repeat count and skip to the end
                done = true;
            } else if (newIteration && !lastIterationFinished) {
                // Time to repeat
                if (mListeners != null) {
                    int numListeners = mListeners.size();
                    for (int i = 0; i < numListeners; ++i) {
                        mListeners.get(i).onAnimationRepeat(this);
                    }
                }
            } else if (lastIterationFinished) {
                done = true;
            }
            mOverallFraction = clampFraction(fraction);
            float currentIterationFraction = getCurrentIterationFraction(mOverallFraction);
            animateValue(currentIterationFraction);
        }
        return done;
    }
    
    @CallSupervoid 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);
            }
        }
    }
    

    我们看到calculateValue(fraction);方法使用PropertyValuesHolder中的calculateValue去计算值。

    未完善,待续。。。

    相关文章

      网友评论

          本文标题:分析Android属性动画源码的执行过程

          本文链接:https://www.haomeiwen.com/subject/wqwbpttx.html