Handler、Looper、Message源码学习总结
一、Handler、Looper、Message三者作用和关系
1、Message
概念:线程中一个个需要处理的任务称为消息,存放任务的是一个队列,成为消息队列(MessageQueue),内部存储结构为单链表。消息是Message类的实例,他有很多个属性,其中有三个需要自己定义:
what:用来标识一条消息
obj:由用户指定,随消息发送的对象。
target:一般指处理消息的Handler
2、Looper
概念:Looper与一个线程绑定,保证线程只有一个Looper对象,Looper只有一个消息对列(MessageQueue)。
主要方法:
prepare()方法主要是初始化一个Looper对象并存储在当前线程中(ThreadLocal),因此该方法只调用一次,否则会抛出异常;
loop()方法是一个阻塞方法,即一个无限循环,他不断地从MessageQueue中取消息,交给message的target的dispatchMessage()处理;如果MessageQueue为null,则一直等待下去。
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
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);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycle();
}
}
3、Handler
概念:Handler的工作主要包含消息的发送和处理过程。消息的发送主要有两种方式:
主要方法:
sendMessage()方法:通过该方法,辗转反则最后获取MessageQueue然后调用了enqueueMessage()方法向消息队列中插入一条消息,MessageQueue的Looper收到消息后回调Message的target的dispatchMessage方法。
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
post(new Runnable())方法:该方法将Runnable对象封装Message(将Runnable对象赋值给msg的callback属性),接着与sendMessage()方法后续一样,调用send的一系列方法将Message插入到消息队列中。
public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
总结:
通过上面的描述可以发现,Android的异步消息处理机制其实就是Handler对消息的发送和处理过程。两种发送方法最终都是将Message添加到MessageQueue(消息对列)中,再由Looper轮询消息队列将消息发送给对应的target处理。那么还牵扯到两个问题:(1)Handler是怎么与MessageQueue建立联系的,即Handler如何获取当前MessageQueue?(2)两种不同的方式发送后,具体的处理过程是怎样的?
二、Handler如何获取当前线程的Looper呢?
在使用Handler之前,我们都是初始化一个Handler实例,在Handler的构造函数中会通过Looper.myLooper()获取当前线程的Looper实例,并通过该实例获取MessageQueue,从而建立了Handler与MessageQueue的联系。这也解释了为什么在线程开始处理任务前必须先调用getLooper()获取Looper对象。(主线程自动初始化Looper,因此不需要手动操作)
三、Handler获取消息后具体的处理过程
前面讲到Looper.loop()方法不断轮询消息队列,只要有Message就通过msg.target.dispatchMessage()方法,将消息传递给相应的target处理。所以我们需要去找dispatchMessage()这个方法的具体实现:
结合前面提到的Handler两种发送方式,
1、当用post(new Runnable())方式时,事实上是将Runnable封装为Message的callback属性,在处理时调用handleCallback(),进而调用run()方法,如下:
private static void handleCallback(Message msg){
msg.callback.run();
}
2、当用sendMessage()方法时,msg.callback就为null,所以检查mCallback是否为空,未定义时mCallback为null,所以最后调用handleMessage()方法进行具体的处理。
mCallback不为null就调用mCallback的handleMessage()方法。Callback是个接口,定义如下:
public interface Callback{
public boolean handleMessage(Message msg);
}
这种方式是告诉我们,通过Callback可以采用如下方式来创建Handler对象:Handler handler = new Handler(callback),这种方式不需要派生Handler子类。
总结:
1、Looper.prepare()在本线程保存一个Looper实例,然后该实例保存一个MessageQueue对象,因为MessageQueue在一个线程只存在一个,因此Looper.prepare()方法只调用一次。
2、Looper.loop()通过一个无限循环,不停地轮询MessageQueue,只要有消息到来,就通过回调msg.target.dispatchMessage()方法将消息传递给对应的target;当MessageQueue为null,就一直等待下去。
3、Handler的构造方法会获取当前线程保存的Looper实例,进而与Looper实例中的MessageQueue相关联。
4、Handler的sendMessage()方法,会给msg的target赋值为handler本身,然后加入MessageQueue中;post(new Runnable())方法会给msg的callback赋值为Runnable,然后加入MessageQueue。
5、在构造Handler实例时,我们要么重写handlerMessage()方法,要么重写run()方法,也就是msg.target.diapatchMessage()最终调用的方法。
参考文章:
https://blog.****.net/lmj623565791/article/details/38377229/
https://www.jianshu.com/p/8ecacbb97af4