android token机制_你真的了解16.6ms刷新机制吗?
閱讀本文前,請(qǐng)您先點(diǎn)擊上面的藍(lán)色字體“Android掃地僧”,“關(guān)注”后再點(diǎn)擊置頂公眾號(hào),優(yōu)質(zhì)干貨,重磅資源第一時(shí)間送達(dá)。
散人丶
https://juejin.im/post/5ce686a46fb9a07ec754f470
前言
之前在整理知識(shí)的時(shí)候,看到android屏幕刷新機(jī)制這一塊,以前一直只是知道,Android每16.6ms會(huì)去刷新一次屏幕,也就是我們常說(shuō)的60fpx,那么問(wèn)題也來(lái)了:
16.6ms刷新一次是什么一次,是以這個(gè)固定的頻率去重新繪制嗎?但是請(qǐng)求繪制的代碼時(shí)機(jī)調(diào)用是不同的,如果操作是在16.6ms快結(jié)束的時(shí)候去繪制的,那么豈不是就是時(shí)間少于16.6ms,也會(huì)產(chǎn)生丟幀的問(wèn)題?再者熟悉繪制的朋友都知道請(qǐng)求繪制是一個(gè)Message對(duì)象,那這個(gè)Message是會(huì)放進(jìn)主線程Looper的隊(duì)列中嗎,那怎么能保證在16.6ms之內(nèi)會(huì)執(zhí)行到這個(gè)Message呢?
文章較長(zhǎng),請(qǐng)耐心觀看,水平不足,如果錯(cuò)誤,還望指出
View ## invalidate()
既然是繪制,那么就從這個(gè)方法看起吧
public void invalidate() { invalidate(true);}public void invalidate(boolean invalidateCache) { invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true);}void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate) { ...... final AttachInfo ai = mAttachInfo; final ViewParent p = mParent; if (p != null && ai != null && l < r && t < b) { final Rect damage = ai.mTmpInvalRect; damage.set(l, t, r, b); p.invalidateChild(this, damage); } ..... }}主要關(guān)注這個(gè)p,最終調(diào)用的是它的invalidateChild()方法,那么這個(gè)p到底是個(gè)啥,ViewParent是一個(gè)接口,那很明顯p是一個(gè)實(shí)現(xiàn)類,答案是ViewRootImpl,我們知道View樹的根節(jié)點(diǎn)是DecorView,那DecorView的Parent是不是ViewRootImpl呢
熟悉Activity啟動(dòng)流程的朋友都知道,Activity 的啟動(dòng)是在 ActivityThread 里完成的,handleLaunchActivity() 會(huì)依次間接的執(zhí)行到 Activity 的 onCreate(), onStart(), onResume()。在執(zhí)行完這些后 ActivityThread 會(huì)調(diào)用 WindowManager#addView(),而這個(gè) addView()最終其實(shí)是調(diào)用了 WindowManagerGlobal 的 addView() 方法,我們就從這里開(kāi)始看,因?yàn)槭请[藏類,所以這里借助Source Insight查看WindowManagerGlobal
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { synchronized (mLock) { ..... root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams); mViews.add(view); mRoots.add(root); mParams.add(wparams); } try { root.setView(view, wparams, panelParentView); } catch (RuntimeException e) { synchronized (mLock) { final int index = findViewLocked(view, false); if (index >= 0) { removeViewLocked(index, true); } } throw e; } } public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { synchronized (this) { .... view.assignParent(this); ... } }void assignParent(ViewParent parent) { if (mParent == null) { mParent = parent; } else if (parent == null) { mParent = null; } }參數(shù)是ViewParent,所以在這里就直接將DecorView和ViewRootImpl給綁定起來(lái)了,所以也驗(yàn)證了上述的結(jié)論,子View里執(zhí)行invalidate()之類的操作,最后都會(huì)走到ViewRootImpl里來(lái)
ViewRootImpl
##scheduleTraversals
根據(jù)上面的鏈路最終是會(huì)執(zhí)行到scheduleTraversals方法
void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); if (!mUnbufferedInputDispatch) { scheduleConsumeBatchedInput(); } notifyRendererOfFramePending(); pokeDrawLockIfNeeded(); } }方法不長(zhǎng),首先如果mTraversalScheduled為false,進(jìn)入判斷,同時(shí)將此標(biāo)志位置位true,第二句暫時(shí)不管,后續(xù)會(huì)講到,主要看postCallback方法,傳遞進(jìn)去了一個(gè)mTraversalRunnable對(duì)象,可以看到這里是一個(gè)請(qǐng)求繪制的Runnable對(duì)象
final class TraversalRunnable implements Runnable { @Override public void run() { doTraversal(); } }void doTraversal() { if (mTraversalScheduled) { mTraversalScheduled = false; mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); if (mProfile) { Debug.startMethodTracing("ViewAncestor"); } performTraversals(); if (mProfile) { Debug.stopMethodTracing(); mProfile = false; } } }doTraversal方法里面,又將mTraversalScheduled置位了false,對(duì)應(yīng)上面的scheduleTraversals方法,可以看到一個(gè)是postSyncBarrier(),而在這里又是removeSyncBarrier(),這里其實(shí)涉及到一個(gè)很有意思的東西,叫同步屏障,等會(huì)會(huì)拉出來(lái)單獨(dú)講解,然后調(diào)用了performTraversals(),這個(gè)方法應(yīng)該都知道了,View 的測(cè)量、布局、繪制都是在這個(gè)方法里面發(fā)起的,代碼邏輯太多了,就不貼出來(lái)了,暫時(shí)只需要知道這個(gè)方法是發(fā)起測(cè)量的開(kāi)始。
這里我們暫時(shí)總結(jié)一下,當(dāng)子View調(diào)用invalidate的時(shí)候,最終是調(diào)用到ViewRootImpl的performTraversals()方法的,performTraversals()方法又是在doTraversal里面調(diào)用的,doTraversal又是封裝在mTraversalRunnable之中的,那么這個(gè)Runnable的執(zhí)行時(shí)機(jī)又在哪呢
Choreographer##postCallback
回到上面的scheduleTraversals方法中,mTraversalRunnable是傳遞進(jìn)了Choreographer的postCallback方法之中
private void postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis) { if (DEBUG_FRAMES) { 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); } }}可以看到內(nèi)部好像有一個(gè)類似MessageQueue的東西,將Runnable通過(guò)delay時(shí)間給存儲(chǔ)起來(lái)的,因?yàn)槲覀冞@里傳遞進(jìn)來(lái)的delay是0,所以執(zhí)行scheduleFrameLocked(now)方法
private void scheduleFrameLocked(long now) { if (!mFrameScheduled) { mFrameScheduled = true; if (isRunningOnLooperThreadLocked()) { scheduleVsyncLocked(); } else { Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC); msg.setAsynchronous(true); mHandler.sendMessageAtFrontOfQueue(msg); } }}private boolean isRunningOnLooperThreadLocked() { return Looper.myLooper() == mLooper;}這里有一個(gè)判斷isRunningOnLooperThreadLocked,看著像是判斷當(dāng)前線程是否是主線程,如果是的話,調(diào)用scheduleVsyncLocked()方法,不是的話會(huì)發(fā)送一個(gè)MSG_DO_SCHEDULE_VSYNC消息,但是最終都會(huì)調(diào)用這個(gè)方法
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); }}如果mReceiverPtr不等于0的話,會(huì)去調(diào)用nativeScheduleVsync(mReceiverPtr),這是個(gè)native方法,暫不跟蹤到C++里面去了,看著英文方法像是一個(gè)安排信號(hào)的意思
之前是把CallBack存儲(chǔ)在一個(gè)Queue之中了,那么必然有執(zhí)行的方法
void doCallbacks(int callbackType, long frameTimeNanos) { CallbackRecord callbacks; synchronized (mLock) { try { Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]); for (CallbackRecord c = callbacks; c != null; c = c.next) { if (DEBUG_FRAMES) { Log.d(TAG, "RunCallback: type=" + callbackType +總結(jié)
以上是生活随笔為你收集整理的android token机制_你真的了解16.6ms刷新机制吗?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: micropython仿真器_Micro
- 下一篇: 存储过程没有执行完后没有释放锁_面试必问