分析过,应用层消息机制 再仔细扒一扒看看,后面继续扒一扒native
Android有大量的消息驱动方式来进行交互,四大组件启动过程交互都离不开消息机制。主要涉及MessageQueue、Message,Looper,Handler四个类
handler要想起作用有三个步骤:
结构图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gO57aH4o-1656519751011)(C:\Users\bafc\AppData\Roaming\Typora\typora-user-images\image-20220628230832580.png)]
public final class Message implements Parcelable {
//当Handler发送多个消息时,用作不同消息处理的区分
public int what;
//当你传输的数据仅仅是int型时优先使用arg1,arg2
public int arg1;
public int arg2;
//Message携带的数据
public Object obj;
//Message执行的延迟时间
public long when;
//处理此Message的目标Handler
Handler target;
//Message的回调,如果设置了此回调,handler的handleMessage方法
//将不会被执行
Runnable callback;
//Message采用链表的形式进行复用,next指向下一个消息
Message next;
//Message消息池的头指针
private static Message sPool;
//Message消息池的大小
private static int sPoolSize = 0;
}
sPool总是指向消息链表的头部,首次创建Message时sPool为空,就需要通过new Message的方式创建Message,我们看下sPool首次是在哪里赋值的,是在recycleUnchecked中,看名字以及注释我们知道此方法是Message使用完毕之后会调用,也就是说我们创建的第一个消息使用完毕之后,会赋值给sPool
public static Message obtain() {
synchronized (sPoolSync) {
//如果sPool不为空,则从消息池取一个Message
if (sPool != null) {
//从消息池中取出头部这个消息
Message m = sPool;
//sPool继续指向下一个消息
sPool = m.next;
//将取出的消息的链断掉
m.next = null;
//修改此消息的flag为0
m.flags = 0; // clear in-use flag
//消息池大小减1
sPoolSize--;
return m;
}
}
return new Message();
}
void recycleUnchecked() {
//当Message使用完成之后会将Message的一系列数据初始化
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
//MAX_POOL_SIZE为50,作为消息池的大小,当sPoolSize没有到50时,
//则此消息应该加入消息池
if (sPoolSize < MAX_POOL_SIZE) {
//如果是第一次消息回收next = sPool = null
next = sPool;
//将当前这个消息赋值给sPool,我们可以看到sPool总是指向
//最后调用recycleUnchecked方法的Message
sPool = this;
//消息池大小加1
sPoolSize++;
}
}
}
从obtain和recycleUnchecked方法中我们能够看出来Message内部消息池采用链表的形式,sPool指向链表的头,每次取出消息是从链表头部开始,每次消息回收也是加在链表头部
public Handler(@Nullable Callback callback, boolean async) {
//获取当前线程的Looper对象,后面分析
mLooper = Looper.myLooper();
//如果Looper为空会抛如下这个异常,这个异常相信Android初学者
//遇见过很多次
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
//获取当前线程Looper的MessageQueue
mQueue = mLooper.mQueue;
//Handler内部回调
mCallback = callback;
//是否是异步消息,后面分析
mAsynchronous = async;
}
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;//构造函数中由looper那里获取
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
//msg.target代表处理此消息的Handler
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
//是否是异步消息,后面分析
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//最终调用MessageQueue的enqueueMessage将此Message投递进MessageQueue
return queue.enqueueMessage(msg, uptimeMillis);
}
// ActivityThread.java
public static void main(String[] args) {
Looper.prepareMainLooper();
.......
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
......
Looper.loop();
}
//Looper.java
public static void prepareMainLooper() {
//注意UI线程调用prepare时传递false,代表不允许Looper退出
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
//通过ThreadLocal保存当前线程的Looper对象,ThreadLocal用来存储线程私有变量,起到线程隔离的目的
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
//创建了MessageQueue,并保存了当前线程
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
//MessageQueue
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
// 从handler那里接上,MessageQueue.java
boolean enqueueMessage(Message msg, long when) {
//如果有message而没有Handler则抛出异常
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
//如果此Message正在使用中则抛出异常
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
//如果MessageQueue正在退出则抛出异常
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
//将此Message添加flag,代表正在使用
msg.markInUse();
//when代表此Message执行的延迟时间
msg.when = when;
//mMessages指向Message消息链表的头部
Message p = mMessages;
//是否需要唤醒
boolean needWake;
//p == null代表此时没有消息,when == 0代表此消息需要立即执行
//when < p.when代表新增加的消息比此时MessageQueue中的消息头
//的消息还要先执行(消息队列的顺序是when最小排在头部,when最大排在尾部)
if (p == null || when == 0 || when < p.when) {
//所以如果进到此条件则代表增加的这条消息是最先执行的,应该加到
//消息队列头部
msg.next = p;
mMessages = msg;
//将当前MessageQueue的状态赋值给needWake,以便能在阻塞时唤醒
//MessageQueue
needWake = mBlocked;
} else {
//p.target == null && msg.isAsynchronous()代表是否开启
//同步屏障,后面分析
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
//循环整个Message链表,将此新增的消息插入到合适位置
for (;;) {
prev = p;
p = p.next;
//当找到p == null代表已经到链表尾部,或者下一个msg的when
//大于当前新增消息的when
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
//链表增加元素的常规操作,断开链next,将msg插入进去
msg.next = p;
prev.next = msg;
}
//唤醒MessageQueue依靠native层
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
enqueueMessage方法其实就是一个链表的插入操作,规则是按照msg的执行时间排序,时间越短越靠近头部
public static void loop() {
//获取当前线程关联的Looper对象
final Looper me = myLooper();
//looper为空则抛出异常
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//获取Looper关联的MessageQueue
final MessageQueue queue = me.mQueue;
//死循环的获取MessageQueue的消息
for (;;) {
//获取消息的核心方法,
Message msg = queue.next(); // might block
//如果获取到的msg为空则说明MessageQueue已经退出,则Looper也需要
//退出循环
if (msg == null) {
return;
}
//待queue.next()方法分析完之后再接着分析后面代码
......
......
}
Message next() {
//mPtr保存native层MessageQueue的指针
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
//nextPollTimeoutMillis代表当前消息的执行时间,0代表立即执行,-1代表
//此时MessageQueue没有消息
int nextPollTimeoutMillis = 0;
//无限循环的取出消息
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//此方法是消息机制的核心,会在下一篇native层消息机制进行分析
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
//获取当前时间
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
//前面分析过,mMessages指向消息链表头部
Message msg = mMessages;
//如果msg不为空handler却为空说明此时Looper需要获取异步消息
if (msg != null && msg.target == null) {
do {
//典型的链表循环
prevMsg = msg;
msg = msg.next;
//退出条件是找到设置了Asynchronous的消息或者
//直到链表尾部也没找到,说明此链表不含异步消息
} while (msg != null && !msg.isAsynchronous());
}
//msg不为空代表此消息链表中是有消息的
if (msg != null) {
//还没到消息执行时间
if (now < msg.when) {
//则重置nextPollTimeoutMillis为等待执行的时间
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {//需要取出消息开始执行
//将mBlocked置为false代表MessageQueue不需要阻塞
mBlocked = false;
//prevMsg指向异步消息前一个消息,不为空代表有异步消息
if (prevMsg != null) {
//链表取出消息的常规操作
prevMsg.next = msg.next;
} else {
//如果没有异步消息,则取出消息队列头部的消息,并让
//mMessages继续指向下一个消息
mMessages = msg.next;
}
//断开取出消息的链
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
//标记此消息为正在使用
msg.markInUse();
//返回取出的消息
return msg;
}
} else {
//消息队列中没有消息
nextPollTimeoutMillis = -1;
}
//如果消息队列退出
if (mQuitting) {
dispose();
return null;
}
//省略的代码是关于pendingIdleHandler的处理,这个handler会在
//MessageQueue为空时执行..不去细看了
.....
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}
Handler消息机制中最重要的消息循环与获取的流程,做一个总结:
public static void loop() {
......
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
return;
}
//省略了很多log相关代码,主要帮助开发者实现监听UI线程卡顿
......
try {
//msg取到之后调用了msg的target也就是handler的dispatchMessage
//方法进行消息处理
msg.target.dispatchMessage(msg);
}
.......
//msg的回收复用,前面已经讲过,此方法会将使用过的msg加入消息池
//进行复用
msg.recycleUnchecked();
}
}
//handler.java
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
最后我们再来看看异步消息,在Android源码绘制流程中使用了异步消息,目的是尽可能快的完成View的绘制
//ViewRootImpl.java
void scheduleTraversals() {
......
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
.....
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
......
}
//Choreographer.java
public void postCallback(int callbackType, Runnable action, Object token) {
postCallbackDelayed(callbackType, action, token, 0);
}
public void postCallbackDelayed(int callbackType,
Runnable action, Object token, long delayMillis) {
......
postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
......
synchronized (mLock) {
.....
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
先调用postSyncBarrier开启同步屏障,屏蔽同步消息,接着设置setAsynchronous为true,将此消息设置为异步,则优先处理异步消息
我们从handler投递msg的分析知道,无论那种投递方式,只要是通过handler的sendXXX方法,最终一定会调用到enqueueMessage方法,
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
此方法第一行代码要做的事就是msg.target = this,而从MessageQueue.next方法中,我们知道要优先处理异步消息有两个条件,一是**(msg != null && msg.target == null),然后才循环消息链表,找到msg.isAsynchronous()为true的msg**,
Message next() {
......
for (;;) {
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
}
......
}
我们可以得出结论,同步屏障就是向MessageQueue投递一个handler为空的msg,有了这个msg,从此msg开始,之后的所有同步消息都会被屏蔽,只会处理isAsynchronous为true的异步消息
//设置FLAG_ASYNCHRONOUS标示此msg为异步消息
public void setAsynchronous(boolean async) {
if (async) {
flags |= FLAG_ASYNCHRONOUS;
} else {
flags &= ~FLAG_ASYNCHRONOUS;
}
}
//开启同步屏障:MessageQueue.java
public int postSyncBarrier() {
return postSyncBarrier(SystemClock.uptimeMillis());
}
private int postSyncBarrier(long when) {
synchronized (this) {
final int token = mNextBarrierToken++;
//创建没有handler的msg
final Message msg = Message.obtain();
msg.markInUse();
//时间是当前系统时间
msg.when = when;
msg.arg1 = token;
Message prev = null;
Message p = mMessages;
if (when != 0) {
//找到晚于当前时间的msg
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
//将新创建的handler为空的msg插入到prev后面
if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
//说明msg应该插到消息头部
msg.next = p;
mMessages = msg;
}
return token;
}
}
我们总结下使用异步消息,两个条件:
en != 0) {
//找到晚于当前时间的msg
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
//将新创建的handler为空的msg插入到prev后面
if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
//说明msg应该插到消息头部
msg.next = p;
mMessages = msg;
}
return token;
}
}
我们总结下使用异步消息,两个条件:
1. 开启同步屏障即投递一个handler为空的msg
2. 将需要发送的msg设置为异步即调用setAsynchronous(true)
同步屏障只能屏蔽消息链表中添加空handler的msg之后的同步消息