Handler是android中跨线程通信的一种方式,最常见的使用场景就是使用handler刷新主线程中的UI界面。 使用方式如下:
Message msg = Message.obtain();
msg.obj = "子线程处理好的数据";
msg.what = 1;
handler.sendMessage(msg);
通过handler的sendMessage方法我们可以很轻易的将数据从子线程发送到主线程,那么Handler究竟是如何将数据从子线程发送到主线程的呢?
接下来带着问题看源码,从handler.sendMessage()方法入手看Handler内部是如何实现跨线程通信的。 点进sendMessage方法:
boolean enqueueMessage(Message msg, long when) {
//如果msg.target 为空,说明这个msg没有目标handler,抛出异常
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
//如果正在使用,抛出异常
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
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;
}
//将该msg状态设置成正在使用
msg.markInUse();
//设置msg的发送时间
msg.when = when;
// mMessages是一个全局的message对象
Message p = mMessages;
boolean needWake;
/**
* p == null: 说明此时队列中没有msg
* when == 0: 当前发送的msg是需要立即执行的
* when < p.when: 当前msg的执行时间小于链表头mMessages的执行时间
* Message是一个链表结构
*/
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
//将当前 msg 的next 指向 mMessages
msg.next = p;
//将当前msg设置为链表中的第一个msg
mMessages = msg;
//是否需要唤醒主线程
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
// 如果新增的msg的执行时间大于表头message的执行时间,就根据执行时间进行排序
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (; ; ) {
prev = p;
p = p.next;
/**
* 直到p == null新增的msg到了队尾
* 或者 when < p.when 直到找到比新增的msg执行时间还大的msg,就跳出循环
*/
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
// 到这里新增的msg就已经成功加入了队列,并且该队列是根据执行时间进行排序的,执行时间最早的排在队首,最晚的在队尾
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
// 唤醒主线程,native方法
nativeWake(mPtr);
}
}
return true;
}
关于Message的结构,message是一个链表结构,感兴趣的同学可以自行了解一下。 代码执行到这里,通过sendMessage发送的msg对象就已经加入到MessageQueque中了,在上面的代码中,最后有一段代码:
if (needWake) {
// 唤醒主线程,native方法
nativeWake(mPtr);
}
这段代码表示的是,通过native方法去唤醒主线程,至于怎么唤醒的,已经深入到了linux底层代码,在这里不做分析。
为什么要唤醒主线程呢?这就涉及到Handler中另外一个重要的对象Looper:
Looper是一个循环器,通过loop方法开启一个死循环
public static void loop() {
//获取当前线程中的looper对象,一个线程中只能存在一个looper对象
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//通过looper对象获取到MessageQueue
final MessageQueue queue = me.mQueue;
...
//开启一个死循环,从 queue 中不断的取message对象
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
try {
/**
* 获取到的msg对象中有一个target对象,该target对象就是在发送消息的handler
* 在Handler的enqueueMessage中对msg.target进行赋值
* 执行target的dispatchMessage方法
*/
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...
}
}
可以看到在loop中是有一个死循环的,如果这个死循环一直在执行,是会严重影响系统的性能的。所以当MessageQueue中没有msg对象的时候,死循环执行一段时间后,系统会让主线程休眠(如何休眠?),让出cpu资源,这样就避免了资源的浪费。当有一个msg被添加到MessageQueue中的时候,会去唤醒主线程,告诉主线程,有一个msg进来了,可以去循环取msg了。然后就会执行取msg的操作,并执行msg.target.dispatchMessage(msg)方法,通过上面的分析可以知道target是一个handler对象,接下来到Handler中看看dispatchMessage方法:
public void dispatchMessage(Message msg) {
/**
* 如果msg中自带callback不为空执行callback中的方法
*/
if (msg.callback != null) {
handleCallback(msg);
} else {
//如果Handler的回调不为空
if (mCallback != null) {
// 执行Handler的回调
if (mCallback.handleMessage(msg)) {
// 如果是使用callback的方式,并在callback中返回true,在这里就会直接return,不会执行Handler的重载方法
return;
}
}
// 执行Handler的重载方法
handleMessage(msg);
}
}
通过上面的分析,就走到了handleMessage方法,到这里就完成了msg从sendMessage到handleMessage的流程,以上是小弟的分析过程,如果有不正确的地方,欢迎各位指正。
android Handler机制解析——Looper和ThreadLoacl: juejin.cn/post/684490…