• 熱門專題

Android6.0WMS(六)WMS動畫管理

作者___258彩票首页:  發布日期|__198注册网址:2016-12-26 20:23:29
Tag標簽__青岛订婚风俗:動畫  
  • Android的應用啟動時_|_江淮愿景iii,或者切換Activity時都會以動畫的方式顯示前後兩屏的切換過程_-谭国箱。動畫的原理很簡單-|丽谯楼,把一幀一幀的圖像按一定時間間隔顯示出來就完成了|-qq2010正式版。

    動畫的繪製需要定時驅動_-_移动3g网络覆盖查询,通常的做法是啟動一個定時消息|-_聚美优品打不开,每隔一定時間發一個消息||移动彩票平台是真的吗,收到消息後輸出一幀畫麵|助赢软件手机版有吗。Android支持VSync信號後__-众博棋牌,動畫的驅動就有VSync信號承擔了-|健贝。

    窗口動畫的基本元素是窗口Surface中保存的圖像气雾剂之家,通過對窗口的Surface設置不同的變換矩陣和透明度361官方网站手机登录,然後強製Surface刷新_众赢国际app是真的吗,就能在屏幕上顯示出窗口的變化過程||印度新娘之真爱无悔。

    Choreographer對象初始化

    我們先來看WMS中的mChoreographer 變量

        final Choreographer mChoreographer = Choreographer.getInstance();

    該變量是一個線程局部存儲變量_||英文版权声明,在它的initialValue中創建了Choreographer對象並返回_-手机qq2009通用版。這裏使用線程局部存儲的目錄就是保證在線程中隻有一個Choreographer對象__-长虹v60。

        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的構造函數||掌上农业银行下载安装,這裏主要是創建了FrameDisplayEventReceiver用來接受VSync信號的對象|__1288彩票正规吗。

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

    FrameDisplayEventReceiver接受VSync信號

    我們在http://blog.csdn.net/kc58236582/article/details/52892384( Android6.0 VSync信號如何到用戶進程 )這篇博客已經分析過FrameDisplayEventReceiver的原理了-|_盈盈彩源代码,當VSync信號過來時|_-苯乙烯用途,最後會調用到FrameDisplayEventReceiver類的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);
            }

    這主要是發送了一個信號-_51促销网,而是是Runnable的那種消息-|俗人岛华人社区。

    因此我們主要看下這個類的run函數|_高敏爱,這裏就是調用了Choreographer的doFrame函數|baby是我歌词。

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

    doFrame函數

    doFrame函數主要有一些VSync時間邏輯處理如果拋棄該VSync信號的話會調用scheduleVsyncLocked函數讓SurfaceFlinger發送一個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立馬發送一個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);//動畫相關
    
                mFrameInfo.markPerformTraversalsStart();
                doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);//power相關
    
                doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
        }

    doCallbacks函數|-许晋龙,我們首先會檢查當前這個CallBackType是否有對應的CallBack回調-_jindon京东商城,如果沒有直接return__|地窖囚奴,如果有的話會調用其回調的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) {//沒有對應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函數
                }
            } 
            ......
        }

    這也就意味著當你沒有CallBackType對應的回調-_快穿拯救深情男配h全文,每次VSync信號過來到doFrame函數再到doCallBacks函數都是沒有意義的|-运盛彩票导航。

    WMS啟動動畫

    那我們下麵看在哪裏把CallBackType對應的回調加入了__寇小宇,這裏我們隻關注動畫相關的-|鹿喜微。

    上麵我們說到VSync會不斷的發送|盘古越狱官网,每秒60多次_-128期看图中肖特,但是動畫不會不停的播放_|ex350,就是這個CallBackType對應的回調沒有--移动彩票官网。哪動畫的啟動和結束也就是受這個影響__tcl手机a998,而就是在WMS中調用scheduleAnimationLocked函數發起的動畫啟動||_咸水湾。

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

    這裏就是調用Choreographer設置CallBackType-|18151期七星彩开奖结果,相關的回調-_钢贸商城网站。這裏我們的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);
        }

    我們最後看postCallbackDelayedInternal函數|-|众赢彩票平台安全吗,就是在mCallBackQueues對應的CallBackType中增加相應的回調__阳光警察。這裏也就是前麵在WMS的scheduleAnimationLocked的參數mAnimator.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函數_|11086移动彩票几年了,我們注意mFrameScheduled這個變量_-|金都西路申徐路,這個時候賦值為true|_-订舱代理,後麵就是用這個變量來控製每次VSync信號過來調用doFrame函數的時候是否要播放動畫

        private void scheduleFrameLocked(long now) {
            if (!mFrameScheduled) {
                mFrameScheduled = true;//注意這個變量
                if (USE_VSYNC) {
                    if (isRunningOnLooperThreadLocked()) {
                        scheduleVsyncLocked();//盡快讓SurfaceFlinger中的EventThread發送一個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不會播放動畫|-_金莎巧克力保质期。

     

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

     

    繼續看postCallbackDelayedInternal函數中增加的回調_仙五破解版,這個回調在WindowAnimator的構造函數中就新建了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);
                    }
                }
            };
        }

    我們最後看回調的run函數_--鸣人堂,如果是FRAME_CALLBACK_TOKEN-_|南京日志,就是調用回調的doFrame函數_-345彩票网邀请码。

        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();
                }
            }
        }


    播放動畫

    在上麵doFrame函數啟動動畫-|_塔罗牌占卜大师 tlpnana,而動畫的播放主要在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);//輸出動畫幀
                    }
                }
    
                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|||九阴真经门派内功,繼續調用WMS的scheduleAnimationLocked播放下一幀
                    mService.scheduleAnimationLocked();
                }
    
                ......
            finally {
                SurfaceControl.closeTransaction();
            }
    
            ......
            boolean doRequest = false;
            if (mBulkUpdateParams != 0) {
                doRequest = mService.copyAnimToLayoutParamsLocked();
            }
    
            if (hasPendingLayoutChanges || doRequest) {
                mService.requestTraversalLocked();//重新刷新UI
            }
    
            if (!mAnimating && wasAnimating) {
                mService.requestTraversalLocked();
            }
        }

    animateLocked方法先將mAnimating 設置為false|--柳州音乐网,然後調用updateWindowsLocked函數和updateWallpaperLocked函數_|小杯文胸,updateWindowsLocked這個函數會調用WindowStateAnimator類的stepAnimationLocker方法-仲博彩票黑过钱吗,如果動畫已經顯示完最後一幀-_1吨水多少立方米,stepAnimationLocker方法將會WindowStateAnimator類的mAnimating設置為false-哈雷摩托车官方网,表示該窗口的動畫已經結束_-_248彩票注册邀请码。而在updateWallpaperLocked函數中會判斷所有窗口的動畫是否已經結束|_-苏西 埃米斯,隻要有一個動畫沒結束|_长途电话前面加什么,就會將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方法繼續顯示動畫__陈奎元简历,否則動畫顯示就結束了-_众赢国际下载。

    下麵我們總結下動畫的播放過程|_金牛区国土局:需要播放動畫時|-_众博网app,先會調用WMS的scheduleAnimationLocked方法-_苏州工业园区三中。調用這個方法後||-银彩娱乐,才會接受並處理一次VSync信號_|广东大专院校排名,對VSync信號的處理_--最美拖哥,就是所有需要繪製的窗口根據各自動畫的誰知重新調整窗口Surface的變化矩陣和透明度_召召与木木;如果還有窗口動畫需要顯示--逛网地图,繼續調用scheduleAnimationLocked方法準備下一幀__|解放军64年前欠条。

    準備一幀動畫的時間可以跨越多個VSync信號周期-多彩宝石图纸,但是隻有收到VSync信號才能更新窗口的Surface的屬性和內容|100担保网博彩,對應用而言收到VSync信號意味著SurfaceFlinger中已經把上次設置的動畫數據取走了_--亿彩有猫腻吗,可以安全地設置下一幀動畫的屬性和內容了|__上海哪有蹦极。

    窗口動畫對象WindowStateAnimator

    窗口對象WindowState中定義了一個類型為WindowStateAnimator的成員變量mWinAnimator_|-128彩票,用來表示窗口的動畫對象|_-耳鸣466专家。

    下麵是一些成員變量

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

    當前正在顯示的動畫有兩種類型-深圳公牛通讯,一種的窗口切換動畫___少女网王世界的旅程,一種是Activity切換動畫|-星光大道娃娃邓丽君,這裏使用了mLocalAnimating和mHasLocalTransformation分別表示窗口動畫的狀態||234彩票网站。

    stepAnimationLocked是WindowStateAnimator類中顯示動畫首先調用的方法_|206 217 214 175,它會初始化WindowStateAnimator對象的一些成員變量

        boolean stepAnimationLocked(long currentTime) {
            final DisplayContent displayContent = mWin.getDisplayContent();
            if (displayContent != null && mService.okToDisplay()) {
    
                if (mWin.isDrawnLw() && mAnimation != null) {//窗口準備好繪製了||_易富彩票首页,窗口動畫對象不為空
                    mHasTransformation = true;
                    mHasLocalTransformation = true;
                    if (!mLocalAnimating) {//還沒有初始化窗口對象
                        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
                        if (mAnimateMove) {
                            mAnimateMove = false;
                            mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),//初始化窗口對象
                                    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代表已經初始化窗口對象
                        mAnimating = true;
                    }
                    if ((mAnimation != null) && mLocalAnimating) {
                        mLastAnimationTime = currentTime;
                        if (stepAnimation(currentTime)) {//通過時間判斷動畫是否顯示完畢
                            return true;
                        }
                    }
                }
                mHasLocalTransformation = false;
                if ((!mLocalAnimating || mAnimationIsEntrance) && mAppAnimator != null//沒有設置窗口動畫或者窗口動畫結束了
                        && mAppAnimator.animation != null) {
                    // 如果有Activity動畫-_五年陈艾,將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;
        }

    該方法的工作就是設置WindowStateAnimator對象的幾個成員變量-|云顶至尊为什么便宜,首先調用WindowState對象的isDrawnLw來判斷窗口係統的狀態--重庆ume官网,隻有準備好了才能顯示|闪吧音源,接著判斷mAnimation是否為空--浦东科普网,不為空代表已經設置好了動畫對象_防火塑料布。

    接下來判斷mLocalAnimating變量的值||陈进平,為false則調用mAnimation的intialize方法來完成動畫對象的初始化(主要設置動畫的高度和寬度)__盈彩网app下载,然後將mLocalAnimating和mAnimating設為true|-众购彩票投注。完成初始化後_3cp彩票平台APP,接著調用stepAnimation方法來判斷動畫是否已經顯示完成_|_刘亦菲色合成图,沒有完成返回true---魏氏膏。

    如果沒有設置動畫或者動畫已經結束了_||衣优库视频,則還有判斷窗口所在的Activity是否還存在動畫|蜡笔小新手机铃声,如果有||旅游鞋品牌,將mAnimating設置true(表示還要繼續播放動畫)_|小爸爸姗姗结局,如果同時mHasTransformation的值仍然為true|_临泉二手房网,或者isAnimating方法返回true|_凤舞摩天麦词,也將mAnimating設置為true_-_易彩集团10元赚钱。

    isAnimating會根據當前動畫對象mAnimation是否為空-|_译乐通,它的附加窗口的動畫對象是否為空-_诛仙入魔任务流程,以及窗口所在的Activity的動畫對象是否為空等條件來判斷-皮肤病医院十大排名,這表示隻要有可能mAnimating就會設置為true-_-360重庆老时时开奖结果。這樣的目的盡量讓動畫完成顯示__熊继柏,即使沒有可顯示的動畫九死一生是什么生肖,多刷新幾次不會有副作用|_苏志变,但如果少畫了一次_1分快3开奖结果今天,屏幕上就可能留下不正確畫麵了_|135彩票平台可靠吗。

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


    我們再看看動畫的生成過程||istoway,WindowStateAnimator的prepareSurfaceLocked方法來完成計算一幀動畫並顯示工作__嫩草老根:
     

        public void prepareSurfaceLocked(final boolean recoveringMemory) {
            ......
            computeShownFrameLocked();//計算要顯示的動畫幀
    
            setSurfaceBoundariesLocked(recoveringMemory);
    
            if (mIsWallpaper && !mWin.mWallpaperVisible) {
                hide();//如果是壁紙窗口_||畅购一卡通,隱藏
            } else if (w.mAttachedHidden || !w.isOnScreen()) {
                hide();//如果窗口不可見_-|22彩票投注app官方下载,隱藏
                ......
            } else if (mLastLayer != mAnimLayer
                    || mLastAlpha != mShownAlpha
                    || mLastDsDx != mDsDx
                    || mLastDtDx != mDtDx
                    || mLastDsDy != mDsDy
                    || mLastDtDy != mDtDy
                    || w.mLastHScale != w.mHScale
                    || w.mLastVScale != w.mVScale
                    || mLastHidden) {//每個值是否有變化
                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()) {//輸出動畫幀
                                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);
                        }
                    }
                }
            }
            ......
        }

    該函數先調用了computeShownFrameLocked函數計算當前需要顯示的動畫幀數據_-御龙在天野蘑菇坐标,mAnimLayer表示窗口的Z軸|--天国凤凰第二部、mShownAlpha窗口透明度|亿发彩票平台靠谱么;mDsDx-_霸气行会名字、mDtDx_-qq下载2011正式版官方免费下载、mDsDy和mDtDy表示二維變換矩陣-|iphone5香港官网;w.mHScale w.mVScale表示窗口的縮放比例

    隻有計算出的數據和上一次數據不一樣才會調用showSurfaceRobustlyLocked輸出動畫幀|--赛尔号鱼龙王刷什么。

延伸閱讀-|-钳子先生的魔法龙虾盒:

About IT165 - 廣告服務 - 隱私聲明 - 版權申明 - 免責條款 - 網站地圖 - 網友投稿 - 聯係方式
本站內容來自於互聯網,僅供用於網絡技術學習,學習中請遵循相關法律法規
秒速牛牛聚鑫彩票荣鼎彩票快乐时时彩順彩彩票大发彩票

免责声明: 本站资料及图片来源互联网文章,本网不承担任何由内容信息所引起的争议和法律责任。所有作品版权归原创作者所有,与本站立场无关,如用户分享不慎侵犯了您的权益,请联系我们告知,我们将做删除处理!