一、handler机制是什么?
handler是Android用于线程间通信的一种机制
主线程运行起来,就会初始化一个Looper对象,Looper对象里有一个MessageQueue对象,
在主线程中new一个Handler对象,子线程中可以调用到主线程的handler对象。因为它是一个成员变量。
主线程new Handler(),就已经获取到了当前线程的Looper对象和MessageQueue对象。
在子线程中通过Message.obtain()方法创建Message对象,通过handler将message对象发(sendMessage()方法)到主线程中的MessageQueue中,
sendMessage()方法会调用到enqueueMessage(),在enqueueMessage方法中,通过msg.target = this; 把handler保存到了Message里面,
最后执行到了消息队列的queue.enqueueMessage方法中去。消息队列的enqueueMessage方法主要是在消息队列中找一个合适的位置,将消息插入到消息队列中
主线程的Looper轮循器在MessageQueue中轮训消息,如果拿到消息了,就调用Looper的loop()方法,Looper的loop方法里
有个无限循环,将消息队列MessageQueue中的消息Message取出,交给msg的target也就是handler,调用handler的dispatchMessage(msg)方法处理。
Looper类:
final MessageQueue mQueue;
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Message类:
public int what; //消息的标记位
public int arg1;
public int arg2; //存储一个int类型的数据
public Object obj; //存储一个对象类型的数据
Handler target;
Runnable callback;
Message next;
public static final Object sPoolSync = new Object();
private static Message sPool; //消息池里的第一条消息,其实是一个存储了消息队列的一个链表
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;//消息池的默认最大数量是50
//从消息池中返回一个消息实例
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
Handler类:
public Handler(@Nullable Callback callback, boolean async) {
mLooper = Looper.myLooper(); //new handler的时候,就已经获取到了当前线程的Looper对象和MessageQueue对象
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
/**
* Subclasses must implement this to receive messages.
* 子类必须重写这个方法来接收消息
*/
public void handleMessage(@NonNull Message msg) {
}
/**
* Handle system messages here.
* 分发消息
*/
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
/**
* Pushes a message onto the end of the message queue after all pending messages
* before the current time. It will be received in {@link #handleMessage},
* in the thread attached to this handler.
* 在当前时间之前所有挂起的消息之后将消息推到消息队列的末尾。它将在附加到该handler的线程中的{@link #handleMessage}中接收。
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
sendMessageDelayed会调用到下面的方法中去:
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,long uptimeMillis) {
msg.target = this; //handler发消息的时候,就把handler保存到了Message里面了
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);//handler发消息的时候,把message保存到MessageQueue中
}
最后执行到了消息队列的queue.enqueueMessage方法中去。
MessageQueue类:
//在消息队列中找一个合适的位置,将消息插入到消息队列中
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
msg.markInUse();
msg.when = when;
Message p = mMessages;//mMessages是消息池里的第一条消息
boolean needWake;
//如果消息队列中没有消息,或者当前消息的时间比队列中的消息的时间小,
//则让当前消息成为队列中的第一条消息
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked. 新头,如果被阻止,唤醒事件队列。
msg.next = p;
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.
// 插入到队列中间。通常我们不需要唤醒事件队列,除非在队列的顶部有一个屏障,
// 并且消息是队列中最早的异步消息。
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
标题
二、怎么从子线程发送消息到主线程?
//在主线程中初始化Handler
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//在此处处理消息
}
};
Thread thread = new Thread(){
@Override
public void run() {
super.run();
//在子线程中发送消息
handler.sendEmptyMessage(0);
}
};
thread.start();
三、怎么从主线程发送消息到子线程?(虽然使用的少)
Thread thread = new Thread(){
@Override
public void run() {
super.run();
//初始化Looper,一定要写在Handler初始化之前
Looper.prepare();
//在子线程内部初始化handler即可,发送消息的代码可在主线程任意地方发送
handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//所有的事情处理完成后要退出looper,即终止Looper循环
//这两个方法都可以,有关这两个方法的区别自行寻找答案
handler.getLooper().quit();
handler.getLooper().quitSafely();
}
};
//启动Looper循环,否则Handler无法收到消息
Looper.loop();
}
};
thread.start();
//在主线程中发送消息
handler.sendMessage();
四、handler的执行逻辑,即handleMessage()方法的执行逻辑,到底是在子线程还是主线程?
答案:handler在哪个线程中发送消息,就在那个线程中执行handleMessage。并不是在handler初始化的线程中执行的。可以从下面分析中找的解释。当我们调用handler.senMessage()方法的时候,最终的结果只是将这个消息插入到了消息队列中,在Looper的loop死循环中(循环的目的是从MessageQueue中取出消息,循环跳出的条件是MessageQueue.next()方法返回了null),通过调用MessageQueue.next()方法取出消息,然后调用message.target对象的dispatchMessage()方法分发消息,而message.target对象也就是上面handler在发送消息时,调用到了enqueMessage方法,在该方法中第一行就对message.target进行了赋值。Looper取出消息后,调用了发送消息的Handler的dispatchMessage()方法,并且将message本身作为参数传了回去。到此时,代码的执行逻辑又回到了Handler中
//Handler的方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
五、一个线程可以有几个Handler?几个Looper?几个MessageQueue?
答案:一个线程中handler对象不限制,但是只可以有一个looper(通过调用Looper的prepare()方法来初始化一个Looper对象),也只能有一个MessageQueue。因为MessageQueue是随着Looper的初始化而初始化的,而且MessageQueue的构造方法是default的,也就是说,只有跟MessageQueue同一个包下才可以实例化MessageQueue,换句话说,我们用户是无法直接new一个MessageQueue对象出来的。而因为Looper在一个线程中只能有一个,从而导致MessageQueue也只能有一个
。
Only one Looper may be created per thread
六、在子线程中new一个handler的时候,必须先调用Looper的prepare方法。最后还要调用Looper的loop方法来循环执行。
七、Looper的Loop()方法到底是不是阻塞操作?如果是?主线程的Looper为什么没有阻塞主线程?如果不是,那你怎么解释Looper.loop()方法?
答案:Activity 的生命周期都有对应的 case 条件了,ActivityThread 有个 getHandler 方法,得到这个 handler 就可以发送消息,然后 loop 里就分发消息,然后就发给 handler, 然后就执行到 H(Handler )里的对应代码。所以这些代码就不会卡死~,有消息过来就能执行。简单的来说:ActivityThread的main方法主要就是做消息循环,一旦退出消息循环,那么你的程序也就可以退出了。
参考文档:
1、https://www.jianshu.com/p/f7cabfe19720
2、https://www.jianshu.com/p/595355e6126d
3、第七个问题:https://www.cnblogs.com/chenxibobo/p/9640472.html