Handler、Looper、MessageQueue
handler在创建的时候,会采用当前线程的looper来构造消息循环系统。handler内部通过ThreadLocal来获取当前线程的Looper。线程默认是没有Looper的,如果需要使用handler,就必须为线程创建Looper。主线程(UI线程),它是ActivityThread,被创建时会初始化Looper,这也是在主线程中默认可以使用handler的原因。如果当前线程中没有Looper而试图使用handler来收发消息,就会报错。
Handler通过sendMessage或者post()等系列方法将消息发送到消息队列(MessageQueue)中,Looper不断轮询消息队列,如果发现有新的消息,则处理,如果没有新的消息,则阻塞。
MessageQueue:
消息队列主要包含两个操作:插入和读取。读取本身伴随着删除操作。插入和读取对应的方法分别为:enQueueMessage和next。MessageQueue虽然叫消息队列,但内部的实现方式并非队列,而是单链表。那么插入和读取消息也就是对单链表的插入和读取。next方法是一个无限循环的方法,如果消息队列中没有消息,那么next方法会一直阻塞在这里。当有新消息到来时,next方法会返回这条消息并将其从单链表中移除。
for
(;;) {
if (nextPollTimeoutMillis != 0 ) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized ( this ) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null ;
Message msg = mMessages ;
if (msg != null && msg. target == null ) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg. next ;
} while (msg != null && !msg.isAsynchronous());
if (nextPollTimeoutMillis != 0 ) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized ( this ) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null ;
Message msg = mMessages ;
if (msg != null && msg. target == null ) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg. next ;
} while (msg != null && !msg.isAsynchronous());
}
Looper的工作原理:
Looper在android的消息机制中扮演着消息循环的角色,具体来说就是它会不停地从Messageq中查看是否有新消息,如果有新消息就会立刻处理,否则就一直阻塞在那里。
可以通过Looper.perpare()方法为当前线程创建一个Looper,通过Looper.loop()来开启消息循环。
Looper可以也是可以退出的,Looper提供quit和quitSafely来退出一个Looper,两者的区别是:quit会直接退出Looper,二quitSafely只是设定一个退出标记,然后把消息队列中已有消息处理完毕后才安全地退出。在子线程中,如果手动为其创建了Looper,那么在所有的事情完成以后应该调用quit方法来终止消息循环,否则这个子线程就会一直处于等待的状态。
loop()方法:
for
(;;) {
Message msg = queue.next(); // might block
if (msg == null ) {
// No message indicates that the message queue is quitting.
return ;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me. mLogging ;
if (logging != null ) {
logging.println( ">>>>> Dispatching to " + msg. target + " " +
msg. callback + ": " + msg. what );
}
Message msg = queue.next(); // might block
if (msg == null ) {
// No message indicates that the message queue is quitting.
return ;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me. mLogging ;
if (logging != null ) {
logging.println( ">>>>> Dispatching to " + msg. target + " " +
msg. callback + ": " + msg. what );
}
msg.target
.dispatchMessage(msg);
...
可以看到,loop()方法也是一个无限循环的方法,它通过消息队列的next方法不断读取队列,前面看到,next()方法是一个没有条件的for循环,如果没有新的消息,会不停阻塞,因此
Message msg = queue.next();
// might block这段代码在没有新的消息进来时会一直阻塞。如果退出消息队列,那么queue.next()方法会返回null,这时就会跳出loop()方法。如果有队列中有新的消息,则会通过
msg.target
.dispatchMessage(msg);这一段,将消息分发给发送消息的handler进行处理。而handler的dispatchMessage方法是在创建Handler时所使用的Looper中执行的,这样就成功把代码逻辑切换到指定的线程中去执行了。
来看一下handler中的dispatchMessage 方法:
public void
dispatchMessage(Message msg) {
if (msg. callback != null ) {
handleCallback(msg);
} else {
if ( mCallback != null ) {
if ( mCallback .handleMessage(msg)) {
return ;
}
}
handleMessage(msg);
if (msg. callback != null ) {
handleCallback(msg);
} else {
if ( mCallback != null ) {
if ( mCallback .handleMessage(msg)) {
return ;
}
}
handleMessage(msg);
}
}
private static void
handleCallback(Message message) {
message. callback .run();
message. callback .run();
}
msg.callback是一个Runnable对象,其实也就是我们在handler.post(Runnable)中传进去的Runnable对象。可以看到,如果我们调用了handler.post(Runnable)方法,那么接下来就会执行该Runnable对象的run方法。如果我们没有传进去Runnable对象,也就是消息是通过handler.sendMessage等其他方式进行发送的,那么就会进入else代码块,其中的mCallback是Handler内部定义的一个接口:
/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
*
* @param msg A {@linkandroid.os.Message Message} object
* @returnTrue if no further handling is desired
*/
public interface Callback {
public boolean handleMessage(Message msg);
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
*
* @param msg A {@linkandroid.os.Message Message} object
* @returnTrue if no further handling is desired
*/
public interface Callback {
public boolean handleMessage(Message msg);
}
通过注释介绍,可以看到,通过使用这个接口,我们在初始化handler时无需实现我们自己的handler子类。什么意思呢?一般我们创建handler时,是通过以下的方式进行创建:
private
Handler
mHandler
=
new
Handler(){
@Override
public void handleMessage(Message msg) {
super .handleMessage(msg);
}
@Override
public void handleMessage(Message msg) {
super .handleMessage(msg);
}
};
这种方式其实也就是我们创建了一个Handler的子类,我们也可以用如下的方式创建一个handler:
private
Handler
mHandler
=
new
Handler(
new
Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
return false ;
}
@Override
public boolean handleMessage(Message msg) {
return false ;
}
});
这种方式就是上面提到的非创建handler子类的形式。继续回到源码中,如果我们使用了这种方式来创建一个Handler,这时mCallback变量则不为null,此时就会调用该对象的handleMessage方法。如果既没有传入Runnable对象,也不是通过设置Callback对象的方式创建的handler,这时就会执行handler自己的handleMessage方法。
总结一下,handler的创建一般有以下几种方式:
1、直接创建一个handler:
private
Handler
mHandler
=
new
Handler();
这种方式下,一般搭配Runnable进行消息的处理:
mHandler.post(
new
Runnable() {
@Override
public void run() {
}
public void run() {
}
});
通过前面的分析我们知道,这时会直接执行run()方法里面的内容。
2、通过Handler子类的方式创建handler:
private
Handler
mHandler2
=
new
Handler(){
@Override
public void handleMessage(Message msg) {
super .handleMessage(msg);
}
@Override
public void handleMessage(Message msg) {
super .handleMessage(msg);
}
};
此时,可以通过sendMessage来进行消息的发送和处理:
mHandler.sendEmptyMessage(
1
);
这时就会执行handleMessage里面的语句
3、通过传入Callback接口创建handler对象:
private
Handler
mHandler
=
new
Handler(
new
Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
return false ;
}
@Override
public boolean handleMessage(Message msg) {
return false ;
}
});
如果该方法返回false,则只会执行Callback对象的handleMessage方法,如果返回为false,还会执行handler自己的handleMessage方法,这点需要留意。
最后需要说明,handler发送消息到消息队列的方式有多种:
mHandler.sendEmptyMessage(
1
);
mHandler.sendMessage( new Message());
mHandler.postDelayed( new Runnable() {
@Override
public void run() {
}
}, 1000 );
mHandler.post( new Runnable() {
@Override
public void run() {
}
mHandler.sendMessage( new Message());
mHandler.postDelayed( new Runnable() {
@Override
public void run() {
}
}, 1000 );
mHandler.post( new Runnable() {
@Override
public void run() {
}
});
所有这些方法最终都会到同一个入口方法:
public boolean
sendMessageAtTime(Message msg,
long
uptimeMillis) {
MessageQueue queue = mQueue ;
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);
MessageQueue queue = mQueue ;
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);
}
也就是将消息插入到消息队列中,接着就会由looper的loop方法对消息进行处理,接下来的流程前面已经分析过了。是否传入Runnable对象,也会影响到消息处理的流程,这个前面也有了详细说明。至此,整个消息处理流程分析完毕。
-----------------------------------------------------------------------------
提个问题,对于下面的代码,哪个会报错:
1)
public class MyThread extends Thread {
private Handler mHandler;
public MyThread() {
mHandler = new Handler();
}
@Override
public void run() {
mHandler.sendEmptyMessage(1);
}
}
2)
public class MyThread extends Thread() {
private Handler mHandler;
@Override
public void run() {
mHandler = new Handler();
mHandler.sendEmptyMessage(1);
}
}
在Activity中分别调用上述两个MyThread(),1)不会报错,2)会报错"Can't create handler inside thread that has not called Looper.prepare()"。
调用new Handler()最终会调用这个方法:
1)中的handler是在子线程的构造函数中初始化的,那么这个handler所在的线程其实并不是MyThread这个线程,而是初始化这个MyThread的线程,在这里也就是UI线程。前面提到,UI线程在ActivityThread的main()方法中已经初始化了它的Looper,因此在上图中的mLooper是存在的,可以成功调用new Handler();
而 2)中的handler是在run方法中初始化的,存在于MyThread这个线程中,该线程在调用new Handler()这个方法之前,并没有初始化自己的Looper,因此会报红框中的错误。
对于上面这个问题,需要明白一点,在线程中,只有在run()方法中的代码是运行在这个线程中,其他部分的代码其实是运行在调用这个线程的线程中。可以参考以下代码:
运行结果:
根据结果可以很明显的看到这一结论。这个可能是java很基础的东西,但我确实是今天才意识到这一点。