Java?Handler同步屏障淺析講解
1.在View的加載和繪制流程這篇文章中:傳送門,有一個(gè)編舞者類,mChoreographer。
mTraversalBarrier = mHandler.getLooper().postSyncBarrier();向MessageQueue中插入一條同步屏障消息,msg.target==null的消息,返回值mTraversalBarrier是一個(gè)int 的token值。
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
//向消息隊(duì)列插入一個(gè)同步屏障的消息。msg.target==null的消息
mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
mChoreographer.postCallback()方法會(huì)執(zhí)行mTraversalRunnable中的代碼。
mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);這個(gè)會(huì)根據(jù)上面產(chǎn)生的token值移出MessageQueue中的同步屏障消息。
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
//移除同步屏障消息
mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
//在這個(gè)方法中會(huì)調(diào)用 measure layout draw,view的繪制繪制流程的方法
performTraversals();
}
}還是看這行代碼mHandler.getLooper().postSyncBarrier(),系統(tǒng)是怎么處理的。
獲取了一個(gè)沒(méi)有設(shè)置handler的Message。
int enqueueSyncBarrier(long when) {
// Enqueue a new sync barrier token.
// We don't need to wake the queue because the purpose of a barrier is to stall it.
synchronized (this) {
final int token = mNextBarrierToken++;
// 這個(gè)msg.target沒(méi)有被賦值
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;
Message prev = null;
Message p = mMessages;
if (when != 0) {
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
}正常我們通過(guò)handler發(fā)送消息,handler是不允許為空的。
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
...........
}
那系統(tǒng)為啥要發(fā)送一個(gè)handler為空的消息呢?
先看mChoreographer發(fā)了同步屏障消息后,又做了什么?
又發(fā)送了一個(gè)異步消息:msg.setAsynchronous(true),這個(gè)消息的handler不為null。
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;
//將消息設(shè)置為異步消息
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}接下來(lái)看看MessageQueue是怎么去消息的,是如何對(duì)這個(gè)同步屏障消息怎么處理的。
Message next() {
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
//如果msg.target==null說(shuō)明我們已經(jīng)向消息隊(duì)里中插入了一條屏障消息。
//此時(shí)會(huì)進(jìn)入到這個(gè)循環(huán)中,找到msg.isAsynchronous==true的異步消息。
//通常我們發(fā)送的都是同步消息isAsynchronous = false的,并且msg.target不能為null的。
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());//msg.isAsynchronous==true時(shí)結(jié)束循環(huán),說(shuō)明找到了這個(gè)異步消息。
}
if (msg != null) {//找到了同步屏障的異步消息后,直接返回
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (false) Log.v("MessageQueue", "Returning message: " + msg);
return msg;
}
} else {//沒(méi)有找到的話則進(jìn)入休眠直到下一次被喚醒
// No more messages.
nextPollTimeoutMillis = -1;
}
}
}在取消的時(shí)候,先判斷進(jìn)行msg.target為null的判斷,然后經(jīng)過(guò)while循環(huán),找到msg.isAsynchronous() == true的消息。也就是上面發(fā)送的異步消息。通常我們發(fā)送的消息都是同步消息,不會(huì)對(duì)對(duì) msg.setAsynchronous(true);進(jìn)行設(shè)置。
系統(tǒng)這樣做的目的就是為了優(yōu)先去處理這個(gè)異步消息。會(huì)把所有的同步消息放在后面,向一道屏障一樣,所以這樣的操作,被稱為同步屏障,是同步屏障消息的處理有更高的優(yōu)先級(jí)。
因?yàn)榫幬枵哳恗Choreographer 負(fù)責(zé)屏幕的渲染,需要及時(shí)的處理從底層過(guò)來(lái)的信號(hào),以保障界面刷新的頻率。
那么mChoreographer是如何處理信號(hào)的,如何進(jìn)行渲染的邏輯是怎么樣的,有機(jī)會(huì)再寫文章進(jìn)行分享。
到此這篇關(guān)于Java Handler同步屏障淺析講解的文章就介紹到這了,更多相關(guān)Java Handler內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何使用Java實(shí)現(xiàn)指定概率的抽獎(jiǎng)
這篇文章主要給大家介紹了關(guān)于如何使用Java實(shí)現(xiàn)指定概率的抽獎(jiǎng)的相關(guān)資料,Java抽獎(jiǎng)程序的基本原理是通過(guò)隨機(jī)數(shù)生成器來(lái)實(shí)現(xiàn)隨機(jī)抽獎(jiǎng)的功能,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-07-07
java調(diào)用shell腳本及注意事項(xiàng)說(shuō)明
這篇文章主要介紹了java調(diào)用shell腳本及注意事項(xiàng)說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
Spring Boot中使用Activiti的方法教程(二)
工作流(Workflow),就是“業(yè)務(wù)過(guò)程的部分或整體在計(jì)算機(jī)應(yīng)用環(huán)境下的自動(dòng)化”,下面這篇文章主要給大家介紹了關(guān)于Spring Boot中使用Activiti的相關(guān)資料,需要的朋友可以參考下2018-08-08
Springmvc DispatcherServlet原理及用法解析
這篇文章主要介紹了Springmvc DispatcherServlet原理及用法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
Java實(shí)現(xiàn)TCP/IP協(xié)議的收發(fā)數(shù)據(jù)(服務(wù)端)代碼實(shí)例
這篇文章主要介紹了Java實(shí)現(xiàn)TCP/IP協(xié)議的收發(fā)數(shù)據(jù)(服務(wù)端)代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11

