題外話android
時光如斯 人世無常 逼哥突然就被 全網封殺數組
難過 尚未去聽過現場 老是感受如今很忙 來日方長 我這種短視動物怎麼屑於把意外這種小几率東西歸入考慮範圍呢 如今和未來這兩個選項悲觀點徹底能翻譯成但願與永別緩存
封殺緣由未知 若是是由於XD 這個自媒體猖獗的時代 是個好時代 它把這個世界本有的模樣赤裸裸矗在你跟前 容許你懷疑思考進步 也是個壞時代 公信力成了僞命題 把人類最後那點遮羞布撕個粉碎 打擊相信人性是正直勇敢美麗的勇氣 若是是由於ZF 嗯 愛我中華bash
針對Android UI不流暢的問題,Google提出了Project Butter對Android的顯示系統進行了重構。 此次重構的三個關鍵點異步
這篇文章咱們主要聊一聊Choregrapher,後續的咱們寫關於其餘。async
界面的顯示大致會通過CPU的計算-> GPU合成柵格化->顯示設備顯示。咱們知道Android設備的刷新頻率通常都是60HZ也就是一秒60次,若是一次繪製在約16毫喵內完成時沒有問題的。可是一旦出現不協調的地方就會出問題以下圖ide
這事不小啊,怎麼解決呢?垂直同步 簡單的說,就是讓CPU計算別沒有計劃沒有規律而是在每一個週期開始的時候開始計算,這樣就有條不紊的有序進行了(以下圖)。這個在android4.1及之後的版本中加入了Choreographer這個類,讓咱們扒開看看他是怎麼實現的。 (Choreographer 這個類的位置android.view.Choreographer) oop
ViewRoot的 doTravle()方法中有這樣一行代碼佈局
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
複製代碼
它的意思就是對整個View樹發起測量佈局繪製操做。關於ViewRootImpl的更多內容這裏就很少介紹了。post
如下方法
最終都會調用 postCallbackDelayedInternal();,那麼咱們就看看這個方法的功能。
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();//獲取當前時間
final long dueTime = now + delayMillis;//到期時間
//將執行動做放在mCallback數組中
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
//若是已經到期就註冊請求垂直同步信號
if (dueTime <= now) {
scheduleFrameLocked(now);
} else {
//若是尚未到期,使用handler在發送一個延時消息。這個延時消息會在到期的時候執行。
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
複製代碼
上一小節,若是已經到期就直接執行scheduleFrameLocked()方法,若是沒有執行就使用mHandler(FrameHandler類型)發送一個what值爲MSG_DO_SCHEDULE_CALLBACK的Message。到期後怎麼執行的呢。這要看FrameHandler怎麼處理的。
private final class FrameHandler extends Handler {
public FrameHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DO_FRAME:
doFrame(System.nanoTime(), 0);
break;
case MSG_DO_SCHEDULE_VSYNC:
doScheduleVsync();
break;
case MSG_DO_SCHEDULE_CALLBACK:
//postCallbackDelayedInternal()方法中當未到期的時候發送過來的
doScheduleCallback(msg.arg1);
break;
}
}
}
複製代碼
以上代碼咱們能夠看出這個,FramHandler拿到 whate屬性值爲MSG_DO_SCHEDULE_CALLBACK的時候會去執行 doScheduleCallback(msg.arg1);方法,跟進去看下
void doScheduleCallback(int callbackType) {
synchronized (mLock) {
if (!mFrameScheduled) {
final long now = SystemClock.uptimeMillis();
if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
scheduleFrameLocked(now);
}
}
}
}
複製代碼
這個方法中先是作了一些判斷,mFrameSceduled爲false 而且hasDueCallbacksLocked()這個方法的返回值爲true,看方法名就能猜出這個callback是否到期了,下面咱們再分析這個。最終若是知足條件的狀況下它會調用 scheduleFrameLocked()這個方法,咦這個方法眼熟不?對,沒錯,postCallbackDelayedInternal()方法中若是到期了的話就直接執行的那個方法。是時候看這個方法裏面搞的什麼事情了。
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;//設置標記位,表示已經安排請求下一幀渲染了。
if (USE_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);
}
}
}
複製代碼
安排垂直同步的具體實現是FrameDisplayEventReceiver類他是DisplayEventReceiver的用於接收垂直信號
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource);
}
@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
mTimestampNanos = timestampNanos;
mFrame = frame;
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);//Message設置爲異步
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
}
複製代碼
接收到垂直同步信號後回調onVsync方法,這個方法使用handler發送帶callback(Runnable類型,自身已繼承)的message,最後run()中也是調用doFrame();(關於這個handler的這個操做詳細信息邏輯,參照下面本文附錄一 handler 分發message
這個message設置爲了異步 (msg.setAsynchronous(true);)這意味這他有優先執行的權利,他是怎麼被優先執行的呢?參照附錄三 message的異步模式
綜上,添加callback流程
void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
if (!mFrameScheduled) {
return; // no work to do
}
//當前時間
startNanos = System.nanoTime();
//當前時間和垂直同步時間
final long jitterNanos = startNanos - frameTimeNanos;
//垂直同步時間和當前時間的差值若是大於一個週期就修正一下
if (jitterNanos >= mFrameIntervalNanos) {
//取插值和始終週期的餘數
final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
//當前時間減去上一步獲得的餘數看成最新的始終信號時間
frameTimeNanos = startNanos - lastFrameOffset;
}
//垂直同步時間上一次時間還小,就安排下次垂直,直接返回
if (frameTimeNanos < mLastFrameTimeNanos) {
scheduleVsyncLocked();
return;
}
mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
mFrameScheduled = false;
mLastFrameTimeNanos = frameTimeNanos;
}
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
mFrameInfo.markInputHandlingStart();
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
mFrameInfo.markAnimationsStart();
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
mFrameInfo.markPerformTraversalsStart();
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
} finally {
AnimationUtils.unlockAnimationClock();
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
if (DEBUG_FRAMES) {
final long endNanos = System.nanoTime();
Log.d(TAG, "Frame " + frame + ": Finished, took "
+ (endNanos - startNanos) * 0.000001f + " ms, latency "
+ (startNanos - frameTimeNanos) * 0.000001f + " ms.");
}
}
複製代碼
當前時間 startNanos = System.nanoTime();
求當前時間和垂直同步時間的差值 :jitterNanos = startNanos - frameTimeNanos;
垂直同步時間和當前時間的差值若是大於一個週期(jitterNanos >= mFrameIntervalNanos)就修正一下
垂直同步時間上一次時間還小,就安排下次渲染: frameTimeNanos < mLastFrameTimeNanos,直接返回
Action包裝在CallbackRecord中,是一個單向列表,按照時間的大小順序排列的。 取出待執行的Actions是經過CallBackQueue的extractDueCallbacksLocked()方法,能夠把CallBackQueue看作是CallBack的管理類,其中還包括添加Action addCallbackLocked(),移除Action removeCallbacksLocked(),是否有帶起的Anction hasDueCallbacksLocked()方法。
private final class CallbackQueue {
//鏈表頭
private CallbackRecord mHead;
//是否存在已經到期的Action
public boolean hasDueCallbacksLocked(long now) {
return mHead != null && mHead.dueTime <= now;
}
//獲取已經到期的Action
public CallbackRecord extractDueCallbacksLocked(long now) {
...
return callbacks;
}
//添加Action
public void addCallbackLocked(long dueTime, Object action, Object token) {
...
}
//移除Action
public void removeCallbacksLocked(Object action, Object token) {
...
}
}
複製代碼
for (CallbackRecord c = callbacks; c != null; c = c.next) {
c.run(frameTimeNanos);
}
複製代碼
從callback中遍歷出CallBcakRecord,挨個執行。
下面是handler分發邏輯,Looper在MessageQueue獲得要執行的message以後就會交給message的target(Handler類型)屬性處理msg.target.dispatchMessage(msg);;
public void dispatchMessage(Message msg) {
//當msg的callback不爲空的時候直接執行msg的callback它是一個Runnable對象
if (msg.callback != null) {
handleCallback(msg);
} else {
//而後再交給mCallBack,它是handler的一個屬性,
//建立Handler的時候能夠選擇傳入一個CallBack對象
//當callBack中handleMessage返回true的時候表示:True if no further handling is desired(不須要進一步處理)
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//當mCallback處理返回爲false的時候纔去執行Handler自身的handleMessage()方法
handleMessage(msg);
}
}
複製代碼
關鍵邏輯在已註釋,小結一下 handler的執行分發Message邏輯
private static void handleCallback(Message message) {
message.callback.run();
}
複製代碼
當咱們使用handler.post(Runnable r)方法時候就是將r設置給message的callback
public interface Callback {
boolean handleMessage(Message msg);
}
複製代碼
3.當messaga 的callBak爲空,且handler的mCallBack爲空的時候就交給本身的handlerMessage()方法執行了。咱們在自定義handler的時候能夠重寫這個方法對message進行相應的操做。
void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
if (!mFrameScheduled) {
return; // no work to do
}
...
...
mFrameScheduled = false;
...
}
複製代碼
「異步模式」的做用就是優先,asynchronous 的message在異步模式下有優先執行的權。
MessageQueue使用postSyncBarrier()方法添加屏障,removeSyncBarrier()方法移除屏障這個兩個方法是成對使用的。
Message next() {
...
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous messagin the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
} ...
return msg;
}
...
複製代碼
完,水平有限,各位不吝批評指正。