Handler机制的作用真的是线程间通信吗?
Handler到底是怎么实现子线程的Message到主线程下被处理的?
郭霖大神的文章:Android异步消息处理机制完全解析,带你从源码的角度彻底理解,详细分析了从sendMessage()到handleMessage()的过程。
handler.sendMessage(msg);
是在子线程的run()方法中执行的,也就是说当前的代码执行环境是子线程,而handleMessage()
方法是运行在主线程的,那么,具体是怎么实现的?
反复看郭霖大神的文章,可以梳理出一个逻辑:
- 在子线程中,产生msg,并获取主线程的Handler,发送msg。
new Thread(new Runnable() {
@Override
public void run() {
Message message = new Message();
message.arg1 = 1;
handler.sendMessage(message);
}
}).start();
- msg最终进入MessageQueue。
final boolean enqueueMessage(Message msg, long when) {
...
//单链表的插入
Message p = mMessages;
msg.next = p;
mMessages = msg;
...
return true;
}
- 主线程一直在轮询MessageQueue,取出刚入队的msg。msg持有handler的引用target,直接msg.target.dispatchMessage()。
public static final void loop() {
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
return;
}
...
msg.target.dispatchMessage(msg);
msg.recycle();
}
}
}
- dispatchMessage()内部调用handleMessage()。
public void dispatchMessage(Message msg) {
...
handleMessage(msg);
}
还是有两个问题没有弄明白:子线程是什么时候结束的?代码从哪里开始进入主线程的运行环境的?为了彻底搞清楚这个问题,只能手写一个handler机制:
Handler.java
public class Handler {
private MessageQueue mQueue;
final Looper mLooper;
public Handler() {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
}
public void handleMessage(Message msg) {
}
public void dispatchMessage(Message msg){
handleMessage(msg);
}
public void sendMessage(Message msg){
MessageQueue queue = mQueue;
if (queue != null) {
enqueueMessage(queue, msg);
}
}
private void enqueueMessage(MessageQueue mQueue, Message msg){
msg.target = this;
mQueue.enqueueMessage(msg);
}
}
Looper.java
public class Looper {
static MessageQueue mQueue;
private static ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private Looper() {
mQueue = new MessageQueue();
}
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
public static Looper myLooper() {
return sThreadLocal.get();
}
public static void loop(){
System.out.println(Thread.currentThread().getName() + ":进入loop()");
Looper looper = myLooper();
for(;;){
Message msg = looper.mQueue.next();
if(msg == null){
continue;
}
msg.target.dispatchMessage(msg);
}
}
}
MessageQueue.java
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
/**
* 互斥队列的通用类
*/
public class MessageQueue {
//声明阻塞队列
private BlockingDeque blockingDeque = new LinkedBlockingDeque(50);
/**
* 入队(生产者)
* @param msg
* @return
*/
public void enqueueMessage(Message msg) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
try {
blockingDeque.put(msg);
System.out.println(Thread.currentThread().getName() + ":msg " + msg.what + " 入队完成");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 出队(消费者)
* @return
*/
public Message next() {
Message msg = null;
try {
System.out.println(Thread.currentThread().getName() + ":MessageQueue.next() ");
msg = (Message) blockingDeque.take();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return msg;
}
}
Test.java
public class Test {
public static void main(String[] args) {
Thread androidMain = new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
System.out.println(Thread.currentThread().getName() + ":handleMessage " + msg.what);
}
};
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
Message message = new Message();
message.what = i;
handler.sendMessage(message);
}
System.out.println(Thread.currentThread().getName() + "运行结束");
}
}).start();
Looper.loop();
System.out.println(Thread.currentThread().getName() + "结束运行");
}
}, "androidMain");
androidMain.start();
}
}
看下运行结果:
从结果中可以得到答案:子线程在所有消息都入队完成后,就结束执行了。主线程一直在运行,Looper#loop()方法体内,已经进入主线程了,无限循环调用MessageQueue#next()方法,next()方法和后面的dispatchMessage()都运行在主线程。
细心的读者会发现,主线程并没退出,这是因为使用了阻塞队列LinkedBlockingDeque。关于阻塞队列,后续再讨论。
从这个手写的Handler,可以发现,MessageQueue的入队方法在子线程中执行,出队方法在主线程中执行。也就是说,同一个对象的不同方法,可以运行在不同的线程中。根据这个原理,我们可以写个更加简单的,子线程给主线程发送消息的例子:
public class SimpleHandler {
volatile Message msg; //注意这里的volatiler
public void loopAndHandleMsg() {
while (true) {
if (msg != null) {
System.out.println(Thread.currentThread().getName() + " 处理消息:" + msg.what);
msg = null;
}
}
}
public void sendMsg(Message msg) {
while (this.msg != null) {
}
this.msg = msg;
System.out.println(Thread.currentThread().getName() + "消息:" + msg.what+"发送完成");
}
}
//Messgae.java文件
public class Message {
int what;
Handler target;
}
//Test.java文件
public class Test {
public static void main(String[] args) {
Thread androidMain = new Thread(new Runnable() {
@Override
public void run() {
SimpleHandler simpleHandler = new SimpleHandler();
new Thread(new Runnable() {
@Override
public void run() {
Message message = new Message();
message.what = 6666;
simpleHandler.sendMsg(message);
Message message2 = new Message();
message2.what = 8888;
simpleHandler.sendMsg(message2);
System.out.println(Thread.currentThread().getName() + "运行结束");
}
}).start();
simpleHandler.loopAndHandleMsg();
System.out.println(Thread.currentThread().getName() + "结束运行");
}
}, "androidMain");
androidMain.start();
}
}
运行结果:
其实,核心就是:Message的产生、发送、存储都是在子线程完成的,而Message的读取,处理是在主线程完成的。这样看来,是不是觉得Handler也没啥神秘的。