You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
81 lines
2.3 KiB
81 lines
2.3 KiB
---
|
|
消息屏障
|
|
---
|
|
|
|
```java
|
|
// 插入屏障
|
|
private int postSyncBarrier(long when){
|
|
synchronized(this){
|
|
final int token = mNextBarrierToken++;
|
|
final Message msg = Message.obtain();
|
|
msg.markInUse();
|
|
msg.when = when;
|
|
msg.arg1 = token;
|
|
return token;
|
|
}
|
|
}
|
|
// 删除屏障
|
|
public void removeSyncBarrier(int token){
|
|
synchronized(this){
|
|
if(needWake && !mQuitting){
|
|
nativeWake(mPtr);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 处理屏障
|
|
Message next(){
|
|
for(;;){
|
|
nativePollOnce(ptr, nextPollTimeoutMillis);
|
|
synchronized(this){
|
|
// 如果第一条消息就是屏障,就往后遍历,看看有没有异步消息
|
|
// 如果没有,就无限休眠,等待被别人唤醒
|
|
// 如果有,就看离这个消息触发时间还有多久,设置一个超时,继续休眠
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
boolean enqueueMessage(Message msg, long when){
|
|
synchronized(this){
|
|
// 给消息插到消息队列
|
|
// 如果插到队列头了,如果当前线程是休眠的,就要唤醒他
|
|
// 如果没插到队列头,如果当前线程是休眠的,并且队列头是屏障
|
|
// 并且当前消息是最早的一条异步消息,就要唤醒线程
|
|
if(needWake){
|
|
nativeWake(mPtr);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
```
|
|
|
|
#### 看几个问题?
|
|
|
|
1. 消息队列为空的时候,插一个屏障,会触发 IdleHandler 嘛?
|
|
2. 如果删除了屏障,消息队列为空了,会触发 IdleHandler 嘛?
|
|
3. 如果消息队列只有一个屏障消息,插一个普通消息会 IdleHandler 嘛?
|
|
4. 如果消息队列只有一个屏障消息,插一个异步消息会 IdleHandler 嘛?
|
|
|
|
Framework 里面哪里用到了消息屏障?
|
|
|
|
```java
|
|
void scheduleTraversals(){
|
|
if(!mTraversalScheduled){
|
|
mTraversalScheduled = true;
|
|
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
|
|
mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
|
|
}
|
|
}
|
|
void doTraversal(){
|
|
if(mTraversalScheduled){
|
|
mTraversalScheduled = false;
|
|
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
|
|
performTraversals();
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 总结
|
|
|
|
1. 消息屏障
|
|
2. 异步消息 |