• 金木棋牌官网

  • 金木棋牌官网

  • 金木棋牌官网

  • 金木棋牌官网

金木棋牌官网

作(zuo)者︰  發(fa)布(bu)日(ri)期︰2020-02-20 03:28:29
Tag標簽︰動(dong)畫  
  • Android的應(ying)用啟動(dong)時,或者切(qie)換Activity時都會以動(dong)畫的方式顯示前後(hou)兩屏的na)謝還(huai)獺6dong)畫的原理很簡單(dan),把一幀一幀的圖像按一定時間(jian)間(jian)隔顯示出來就完成了。

    動(dong)畫的繪(hui)制需要定時驅動(dong),通(tong)常的做法是啟動(dong)一個定時消息,每隔一定時間(jian)發(fa)一個消息,收到消息後(hou)輸出一幀畫面。Android支持VSync信號後(hou),動(dong)畫的na)dong)就有(you)VSync信號承擔(dan)了。

    窗口(kou)動(dong)畫的基本元素是窗口(kou)Surface中保存的圖像,通(tong)過對yuan)翱kou)的Surface設置不同的變換矩(ju)陣和透明度,然後(hou)強制Surface刷新,就能在屏幕上顯示出窗口(kou)的變化過程。

    金木棋牌官网

    我們先(xian)來看WMS中的mChoreographer 變量(liang)

     final Choreographer mChoreographer = Choreographer.getInstance();

    該變量(liang)是一個線程局(ju)部存儲變量(liang),在它(ta)的initialValue中創建(jian)了Choreographer對象並返回。這(zhe)里使用線程局(ju)部存儲的目(mu)錄(lu)就是保證在線程中只有(you)一個Choreographer對象。

     public static Choreographer getInstance() { return sThreadInstance.get(); }
     private static final ThreadLocal<Choreographer> sThreadInstance =  new ThreadLocal<Choreographer>() { @Override protected Choreographer initialValue() {  Looper looper = Looper.myLooper();  if (looper == null) {  throw new IllegalStateException("The current thread must have a looper!");  }  return new Choreographer(looper); } };

    再來看下Choreographer的構造(zao)函數,這(zhe)里主要是創建(jian)了FrameDisplayEventReceiver用來接受(shou)VSync信號的對象。

     private Choreographer(Looper looper) { mLooper = looper; mHandler = new FrameHandler(looper); mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;//接受(shou)VSync信號對象 mLastFrameTimeNanos = Long.MIN_VALUE; mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());//計算刷新的時間(jian)間(jian)隔 mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1]; for (int i = 0; i <= CALLBACK_LAST; i++) {  mCallbackQueues[i] = new CallbackQueue(); } }

    金木棋牌官网

    我們在http://blog.csdn.net/kc58236582/article/details/52892384( Android6.0 VSync信號如何到用戶進程 )這(zhe)篇(pian)博客已經分析過FrameDisplayEventReceiver的原理了,當VSync信號過來時,最(zui)後(hou)會調用到FrameDisplayEventReceiver類(lei)的onVsync函數︰

     @Override public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {  if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {  scheduleVsync();  return;  }  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); }

    這(zhe)主要是發(fa)送(song)了一個信號,而是是Runnable的那(na)種消息。

    因此我們主要看下這(zhe)個類(lei)的run函數,這(zhe)里就是調用了Choreographer的doFrame函數。

     @Override public void run() {  mHavePendingVsync = false;  doFrame(mTimestampNanos, mFrame); }

    金木棋牌官网

    doFrame函數主要有(you)一些(xie)VSync時間(jian)邏輯處(chu)理如果拋棄該VSync信號的話(hua)會調用scheduleVsyncLocked函數讓SurfaceFlinger發(fa)送(song)一個VSync信號,如果正常會調用4個doCallBacks函數。

     void doFrame(long frameTimeNanos, int frame) { final long startNanos; synchronized (mLock) {  ......  long intendedFrameTimeNanos = frameTimeNanos;  startNanos = System.nanoTime();  final long jitterNanos = startNanos frameTimeNanos;  if (jitterNanos >= mFrameIntervalNanos) {  final long skippedFrames = jitterNanos / mFrameIntervalNanos;  final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;  frameTimeNanos = startNanos lastFrameOffset;  }  if (frameTimeNanos < mLastFrameTimeNanos) {  if (DEBUG_JANK) {   Log.d(TAG, "Frame time appears to be going backwards. May be due to a "    + "previously skipped frame. Waiting for next vsync.");  }  scheduleVsyncLocked();//讓SurfaceFlinger立(li)馬發(fa)送(song)一個VSync信號  return;  }  mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);  mFrameScheduled = false;  mLastFrameTimeNanos = frameTimeNanos; } try {  Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");  mFrameInfo.markInputHandlingStart();  doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);//按鍵相關  mFrameInfo.markAnimationsStart();  doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);//動(dong)畫相關  mFrameInfo.markPerformTraversalsStart();  doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);//power相關  doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos); } finally {  Trace.traceEnd(Trace.TRACE_TAG_VIEW); } }

    doCallbacks函數,我們首(shou)先(xian)會檢查當前這(zhe)個CallBackType是否有(you)對應(ying)的CallBack回調,如果沒有(you)直接return,如果有(you)的話(hua)會調用其回調的run函數。

     void doCallbacks(int callbackType, long frameTimeNanos) { CallbackRecord callbacks; synchronized (mLock) {  final long now = System.nanoTime();  callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(   now / TimeUtils.NANOS_PER_MS);  if (callbacks == null) {//沒有(you)對應(ying)CallBack回調  return;  }  mCallbacksRunning = true;  // safe by ensuring the commit time is always at least one frame behind.  if (callbackType == Choreographer.CALLBACK_COMMIT) {  final long jitterNanos = now frameTimeNanos;  Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);  if (jitterNanos >= 2 * mFrameIntervalNanos) {   final long lastFrameOffset = jitterNanos % mFrameIntervalNanos    + mFrameIntervalNanos;   if (DEBUG_JANK) {   mDebugPrintNextFrameTimeDelta = true;   }   frameTimeNanos = now lastFrameOffset;   mLastFrameTimeNanos = frameTimeNanos;  }  } } try {  for (CallbackRecord c = callbacks; c != null; c = c.next) {  c.run(frameTimeNanos);//調用回調run函數  } }  ...... }

    這(zhe)也就意味著當你沒有(you)CallBackType對應(ying)的回調,每次VSync信號過來到doFrame函數再到doCallBacks函數都是沒有(you)意義(yi)的。

    金木棋牌官网

    那(na)我們下面看在哪里把CallBackType對應(ying)的回調加入了,這(zhe)里我們只huai)刈 dong)畫相關的。

    上面我們說(shuo)到VSync會不斷xi)姆fa)送(song),每秒60多次,但是動(dong)畫不會不停的播(bo)放,就是這(zhe)個CallBackType對應(ying)的回調沒有(you)。哪動(dong)畫的啟動(dong)和結束也就是受(shou)這(zhe)個影(ying)響(xiang),而就是在WMS中調用scheduleAnimationLocked函數發(fa)起的動(dong)畫啟動(dong)。

     void scheduleAnimationLocked() { if (!mAnimationScheduled) {  mAnimationScheduled = true;  mChoreographer.postFrameCallback(mAnimator.mAnimationFrameCallback); } }

    這(zhe)里就是調用Choreographer設置CallBackType,相關的回調。這(zhe)里我們的callbackType是CALLBACK_ANIMATION

     public void postFrameCallback(FrameCallback callback) { postFrameCallbackDelayed(callback, 0); } public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) { if (callback == null) {  throw new IllegalArgumentException("callback must not be null"); } postCallbackDelayedInternal(CALLBACK_ANIMATION,  callback, FRAME_CALLBACK_TOKEN, delayMillis); }

    我們最(zui)後(hou)看postCallbackDelayedInternal函數,就是在mCallBackQueues對應(ying)的CallBackType中增加相應(ying)的回調。這(zhe)里也就是前面在WMS的scheduleAnimationLocked的參wen)Animator.mAnimationFrameCallback就是回調。

     private void postCallbackDelayedInternal(int callbackType,  Object action, Object token, long 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);  } } }

    我們來看下scheduleFrameLocked函數,我們注意mFrameScheduled這(zhe)個變量(liang),這(zhe)個時候賦值為true,後(hou)面就是用這(zhe)個變量(liang)來控制每次VSync信號過來調用doFrame函數的時候是否要播(bo)放動(dong)畫

     private void scheduleFrameLocked(long now) { if (!mFrameScheduled) {  mFrameScheduled = true;//注意這(zhe)個變量(liang)  if (USE_VSYNC) {  if (isRunningOnLooperThreadLocked()) {   scheduleVsyncLocked();//盡快讓SurfaceFlinger中的EventThread發(fa)送(song)一個VSync信號  } 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);  } } }

    我們再回過頭來看doFrame函數,當mFrameScheduled為false時,VSync信號過來該函數直接return不會播(bo)放動(dong)畫。

     

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

     

    繼續(xu)看postCallbackDelayedInternal函數中增加的回調,這(zhe)個回調在WindowAnimator的構造(zao)函數中就新建(jian)了Choreographer.FrameCallback回調

     WindowAnimator(final WindowManagerService service) { mService = service; mContext = service.mContext; mPolicy = service.mPolicy; mAnimationFrameCallback = new Choreographer.FrameCallback() {  public void doFrame(long frameTimeNs) {  synchronized (mService.mWindowMap) {   mService.mAnimationScheduled = false;   animateLocked(frameTimeNs);  }  } }; }

    我們最(zui)後(hou)看回調的run函數,如果是FRAME_CALLBACK_TOKEN,就是調用回調的doFrame函數。

     private static final class CallbackRecord { public CallbackRecord next; public long dueTime; public Object action; // Runnable or FrameCallback public Object token; public void run(long frameTimeNanos) {  if (token == FRAME_CALLBACK_TOKEN) {  ((FrameCallback)action).doFrame(frameTimeNanos);  } else {  ((Runnable)action).run();  } } }


    播(bo)放動(dong)畫

    在上面doFrame函數啟動(dong)動(dong)畫,而動(dong)畫的播(bo)放主要在WindowAnimator的animateLocked函數。

     private void animateLocked(long frameTimeNs) { ...... boolean wasAnimating = mAnimating; mAnimating = false;//設置mAnimating為false mAppWindowAnimating = false; SurfaceControl.openTransaction(); SurfaceControl.setAnimationTransaction(); try {  final int numDisplays = mDisplayContentsAnimators.size();  for (int i = 0; i < numDisplays; i++) {  final int displayId = mDisplayContentsAnimators.keyAt(i);  updateAppWindowsLocked(displayId);  ......  // Update animations of all applications, including those  // associated with exiting/removed apps  updateWindowsLocked(displayId);  updateWallpaperLocked(displayId);  final WindowList windows = mService.getWindowListLocked(displayId);  final int N = windows.size();  for (int j = 0; j < N; j++) {   windows.get(j).mWinAnimator.prepareSurfaceLocked(true);//輸出動(dong)畫幀  }  }  for (int i = 0; i < numDisplays; i++) {  final int displayId = mDisplayContentsAnimators.keyAt(i);  testTokenMayBeDrawnLocked(displayId);  final ScreenRotationAnimation screenRotationAnimation =   mDisplayContentsAnimators.valueAt(i).mScreenRotationAnimation;  if (screenRotationAnimation != null) {   screenRotationAnimation.updateSurfacesInTransaction();  }  mAnimating = mService.getDisplayContentLocked(displayId).animateDimLayers();  if (mService.mAccessibilityController != null   && displayId == Display.DEFAULT_DISPLAY) {   mService.mAccessibilityController.drawMagnifiedRegionBorderIfNeededLocked();  }  }  if (mAnimating) {//為true,繼續(xu)調用WMS的scheduleAnimationLocked播(bo)放下一幀  mService.scheduleAnimationLocked();  }  ...... finally {  SurfaceControl.closeTransaction(); } ...... boolean doRequest = false; if (mBulkUpdateParams != 0) {  doRequest = mService.copyAnimToLayoutParamsLocked(); } if (hasPendingLayoutChanges doRequest) {  mService.requestTraversalLocked();//重(zhong)新刷新UI } if (!mAnimating && wasAnimating) {  mService.requestTraversalLocked(); } }

    animateLocked方法先(xian)將mAnimating 設置為false,然後(hou)調用updateWindowsLocked函數和updateWallpaperLocked函數,updateWindowsLocked這(zhe)個函數會調用WindowStateAnimator類(lei)的stepAnimationLocker方法,如果動(dong)畫已經顯示完最(zui)後(hou)一幀,stepAnimationLocker方法將會WindowStateAnimator類(lei)的mAnimating設置為false,表示該窗口(kou)的動(dong)畫已經結束。而在updateWallpaperLocked函數中會判斷所有(you)窗口(kou)的動(dong)畫是否已經結束,只要有(you)一個動(dong)畫沒結束,就會將winAnimator的mAnimating設置為true。

     for (int i = windows.size() 1; i >= 0; i) {  final WindowState win = windows.get(i);  WindowStateAnimator winAnimator = win.mWinAnimator;  if (winAnimator.mSurfaceControl == null) {  continue;  }  final int flags = win.mAttrs.flags;  if (winAnimator.mAnimating) {  ......  mAnimating = true;  } ......

    再回到animatelocked方法,當mAnimating為true是會調用WMS的scheduleAnimationLocked方法繼續(xu)顯示動(dong)畫,否則動(dong)畫顯示就結束了。

    下面我們總結下動(dong)畫的播(bo)放過程︰需要播(bo)放動(dong)畫時,先(xian)會調用WMS的scheduleAnimationLocked方法。調用這(zhe)個方法後(hou),才(cai)會接受(shou)並處(chu)理一次VSync信號,對VSync信號的處(chu)理,就是所有(you)需要繪(hui)制pin)拇翱kou)根據(ju)各(ge)自動(dong)畫的誰知重(zhong)新調整窗口(kou)Surface的變化矩(ju)陣和透明度;如果還(huai)有(you)窗口(kou)動(dong)畫需要顯示,繼續(xu)調用scheduleAnimationLocked方法準備下一幀。

    準備一幀動(dong)畫的時間(jian)可(ke)以跨越(yue)多個VSync信號周(zhou)期,但是只有(you)收到VSync信號才(cai)能更新窗口(kou)的Surface的屬性和內容,對應(ying)用而言收到VSync信號意味著SurfaceFlinger中已經把上次設置的動(dong)畫數據(ju)取(qu)走了,可(ke)以安全地設置下一幀動(dong)畫的屬性和內容了。

    金木棋牌官网

    窗口(kou)對象WindowState中定義(yi)了一個類(lei)型為WindowStateAnimator的成員變量(liang)mWinAnimator,用來表示窗口(kou)的動(dong)畫對象。

    下面是一些(xie)成員變量(liang)

     boolean mAnimating;//表示是否正在顯示動(dong)畫 boolean mLocalAnimating;//表示窗口(kou)動(dong)畫是否已經初始化 Animation mAnimation;//表示窗口(kou)動(dong)畫對象 boolean mAnimationIsEntrance;// boolean mHasTransformation;//表示當前動(dong)畫的mTransformation是否可(ke)用 boolean mHasLocalTransformation;//表示當前動(dong)畫時一個窗口(kou)動(dong)畫還(huai)是Activity動(dong)畫 final Transformation mTransformation = new Transformation();//變換矩(ju)陣對象

    當前正在顯示的動(dong)畫有(you)兩種類(lei)型,一種的窗口(kou)切(qie)換動(dong)畫,一種是Activity切(qie)換動(dong)畫,這(zhe)里使用了mLocalAnimating和mHasLocalTransformation分別表示窗口(kou)動(dong)畫的狀(zhuang)態。

    stepAnimationLocked是WindowStateAnimator類(lei)中顯示動(dong)畫首(shou)先(xian)調用的方法,它(ta)會初始化WindowStateAnimator對象的一些(xie)成員變量(liang)

     boolean stepAnimationLocked(long currentTime) { final DisplayContent displayContent = mWin.getDisplayContent(); if (displayContent != null && mService.okToDisplay()) {  if (mWin.isDrawnLw() && mAnimation != null) {//窗口(kou)準備好繪(hui)制了,窗口(kou)動(dong)畫對象不為空  mHasTransformation = true;  mHasLocalTransformation = true;  if (!mLocalAnimating) {//還(huai)沒有(you)初始化窗口(kou)對象   final DisplayInfo displayInfo = displayContent.getDisplayInfo();   if (mAnimateMove) {   mAnimateMove = false;   mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),//初始化窗口(kou)對象    mAnimDw, mAnimDh);   } else {   mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),    displayInfo.appWidth, displayInfo.appHeight);   }   mAnimDw = displayInfo.appWidth;   mAnimDh = displayInfo.appHeight;   mAnimation.setStartTime(mAnimationStartTime != 1    ? mAnimationStartTime    : currentTime);   mLocalAnimating = true;// 設置為true代表已經初始化窗口(kou)對象   mAnimating = true;  }  if ((mAnimation != null) && mLocalAnimating) {   mLastAnimationTime = currentTime;   if (stepAnimation(currentTime)) {//通(tong)過時間(jian)判斷動(dong)畫是否顯示完畢   return true;   }  }  }  mHasLocalTransformation = false;  if ((!mLocalAnimating mAnimationIsEntrance) && mAppAnimator != null//沒有(you)設置窗口(kou)動(dong)畫或者窗口(kou)動(dong)畫結束了   && mAppAnimator.animation != null) {  // 如果有(you)Activity動(dong)畫,將mAnimating設為true  mAnimating = true;  mHasTransformation = true;  mTransformation.clear();  return false;  } else if (mHasTransformation) {  // Little trick to get through the path below to act like  // we have finished an animation.  mAnimating = true;  } else if (isAnimating()) {  mAnimating = true;  } } else if (mAnimation != null) {  mAnimating = true; } if (!mAnimating && !mLocalAnimating) {  return false; } mAnimating = false; mKeyguardGoingAwayAnimation = false; mAnimatingMove = false; mLocalAnimating = false; ...... mHasLocalTransformation = false; ...... mTransformation.clear(); ...... return false; }

    該方法的工作(zuo)就是設置WindowStateAnimator對象的幾個成員變量(liang),首(shou)先(xian)調用WindowState對象的isDrawnLw來判斷窗口(kou)系(xi)統(tong)的狀(zhuang)態,只有(you)準備好了才(cai)能顯示,接著判斷mAnimation是否為空,不為空代表已經設置好了動(dong)畫對象。

    接下來判斷mLocalAnimating變量(liang)的值dan) alse則調用mAnimation的intialize方法來完成動(dong)畫對象的初始化(主要設置動(dong)畫的高度和寬度),然後(hou)將mLocalAnimating和mAnimating設為true。完成初始化後(hou),接著調用stepAnimation方法來判斷動(dong)畫是否已經顯示完成,沒有(you)完成返回true。

    如果沒有(you)設置動(dong)畫或者動(dong)畫已經結束了,則還(huai)有(you)判斷窗口(kou)所在的Activity是否還(huai)存在動(dong)畫,如果有(you),將mAnimating設置true(表示還(huai)要繼續(xu)播(bo)放動(dong)畫),如果同時mHasTransformation的值仍然為true,或者isAnimating方法返回true,也將mAnimating設置為true。

    isAnimating會根據(ju)當前動(dong)畫對象mAnimation是否為空,它(ta)的附加窗口(kou)的動(dong)畫對象是否為空,以及窗口(kou)所在的Activity的動(dong)畫對象是否為空等條(tiao)件來判斷,這(zhe)表示ju)灰 you)可(ke)能mAnimating就會設置為true。這(zhe)樣(yang)的目(mu)的盡量(liang)讓動(dong)畫完成顯示,即(ji)使沒有(you)可(ke)顯示的動(dong)畫,多刷新lu)復尾換嵊you)副作(zuo)用,但如果少畫了一次,屏幕上就可(ke)能留下不正確(que)畫面了。

     boolean isAnimating() { return mAnimation != null   (mAttachedWinAnimator != null && mAttachedWinAnimator.mAnimation != null)   (mAppAnimator != null && mAppAnimator.isAnimating()); }


    我們再看看動(dong)畫的生成過程,WindowStateAnimator的prepareSurfaceLocked方法來完成計算一幀動(dong)畫並顯示jing)?zuo)︰
     

     public void prepareSurfaceLocked(final boolean recoveringMemory) { ...... computeShownFrameLocked();//計算要顯示的動(dong)畫幀 setSurfaceBoundariesLocked(recoveringMemory); if (mIsWallpaper && !mWin.mWallpaperVisible) {  hide();//如果是壁紙窗口(kou),隱藏 } else if (w.mAttachedHidden !w.isOnScreen()) {  hide();//如果窗口(kou)不可(ke)見,隱藏  ...... } else if (mLastLayer != mAnimLayer   mLastAlpha != mShownAlpha   mLastDsDx != mDsDx   mLastDtDx != mDtDx   mLastDsDy != mDsDy   mLastDtDy != mDtDy   w.mLastHScale != w.mHScale   w.mLastVScale != w.mVScale   mLastHidden) {//每個值是否有(you)變化  displayed = true;  mLastAlpha = mShownAlpha;  mLastLayer = mAnimLayer;  mLastDsDx = mDsDx;  mLastDtDx = mDtDx;  mLastDsDy = mDsDy;  mLastDtDy = mDtDy;  w.mLastHScale = w.mHScale;  w.mLastVScale = w.mVScale;  if (mSurfaceControl != null) {  try {   mSurfaceAlpha = mShownAlpha;   mSurfaceControl.setAlpha(mShownAlpha);   mSurfaceLayer = mAnimLayer;   mSurfaceControl.setLayer(mAnimLayer);   mSurfaceControl.setMatrix(    mDsDx * w.mHScale, mDtDx * w.mVScale,    mDsDy * w.mHScale, mDtDy * w.mVScale);   if (mLastHidden && mDrawState == HAS_DRAWN) {   if (showSurfaceRobustlyLocked()) {//輸出動(dong)畫幀    mLastHidden = false;    if (mIsWallpaper) {    mService.dispatchWallpaperVisibility(w, true);    }    mAnimator.setPendingLayoutChanges(w.getDisplayId(),     WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);   } else {    w.mOrientationChanging = false;   }   }   if (mSurfaceControl != null) {   w.mToken.hasVisible = true;   }  } catch (RuntimeException e) {   Slog.w(TAG, "Error updating surface in " + w, e);   if (!recoveringMemory) {   mService.reclaimSomeSurfaceMemoryLocked(this, "update", true);   }  }  } } ...... }

    該函數先(xian)調用了computeShownFrameLocked函數計算當前需要顯示的動(dong)畫幀數據(ju),mAnimLayer表示窗口(kou)的Z軸、mShownAlpha窗口(kou)透明度;mDsDx、mDtDx、mDsDy和mDtDy表示二維變換矩(ju)陣;w.mHScale w.mVScale表示窗口(kou)的縮放比例

    只有(you)計算出的數據(ju)和上一次wen)ju)不一樣(yang)才(cai)會調用showSurfaceRobustlyLocked輸出動(dong)畫幀。

About IT165 -廣(guang)告服(fu)務(wu) -隱私聲明 -版權申明 -免(mian)責條(tiao)款 -網站地圖 -網友投稿 -聯系(xi)方式
本站內容來自于互聯網,僅供用于網絡技(ji)術(shu)學習,學習中請(qing)遵循相關法律法規
金木棋牌官网 | 下一页