Handler运行机制
Handler运行机制是Android消息处理机制的上层接口. 依靠Looper, MessageQueue, Message支撑/协作.在主线程中不能放置耗时任务, 否则会引起ANR. 所以一般耗时任务会放在子线程当中. 由于Android开发规范, 在子线程中不能进行UI操作. 不可避免地涉及进行线程之间通信问题. 所以有人说, Handler运行机制就是用来处理UI线程与子线程之间的通信的. 这仅仅是Handler运行机制的一个应用场景. 比如还可以实现子线程向子线程发送消息, 可以参考下这篇文章.
四个重要角色 Message
Message
是消息的载体, 比较重要的两个字段是obj
与 what
字段, obj
就是需要传递消息的内容, what
标志消息的类型, 方便在接收的时候处理.MessageQueue
存储
Meesage
的单链表, 向外提供读取next
方法, 与enqueueMessage
入队操作.Looper
维护
MessageQueue
, 开始工作时, 不断从MessageQueue
中取出Message
分发给他们的target
(其实就是他们对应的handler
). 一个线程中只能有一个Looper对象.Handler
消息的发送者与消息的处理者
一个经典的例子
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
这里通过继承
Thread
,创建了一个LooperThread
的线程类, run
方法中先调用了Looper.prepare()
, 然后创建了一个Handler对象, 最后调用了Looper.loop()
方法.接下来, 我们通过源码分析看看究竟发生了什么.
Looper.Prepare
public static void prepare() {
prepare(true);
}private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
可以看到
prepare
方法可以重载, 先会判断sThreadLocal.get()
是否为空, 为空的话, 先new Looper(quitAllowed)
创建了一个Looper对象, 然后把这个Looper对象保存在了sThreadLocal
中. 可以想象当我们再次在当前线程调用Looper.prepare
方法时, 这时的sThreadLocal.get()
就不为空了, 会向我们抛出一个Only one Looper may be created per thread
异常. 由此可以保证我们每个线程最多拥有一个Looper对象.刚才构造Looper对象的过程中, 究竟又做了什么呢?
我们看看Looper的构造方法
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
可以看到内容只有两行. 分别为Looper的两个成员变量赋值, 创建了一个MessageQueue, Looper绑定了当前线程.
总结下就是:
Looper.prepare
方法在当前线程中创建了一个Looper
对象, Looper
对象的创建又导致了MessageQueue
对象创建. 并且绑定当前线程. (Looper和MessageQueue在一个线程中最多有一个)创建Handler对象 Handler对象的创建我们直接来看Handler的构造方法.
/**
* Default constructor associates this handler with the {@link Looper} for the
* current thread.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*/
public Handler() {
this(null, false);
}/**
* Constructor associates this handler with the {@link Looper} for the
* current thread and takes a callback interface in which you can handle
* messages.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*
* @param callback The callback interface in which to handle messages, or null.
*/
public Handler(Callback callback) {
this(callback, false);
}/**
* Use the provided {@link Looper} instead of the default one.
*
* @param looper The looper, must not be null.
*/
public Handler(Looper looper) {
this(looper, null, false);
}/**
* Use the provided {@link Looper} instead of the default one and take a callback
* interface in which to handle messages.
*
* @param looper The looper, must not be null.
* @param callback The callback interface in which to handle messages, or null.
*/
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}/**
* Use the {@link Looper} for the current thread
* and set whether the handler should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages.Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
public Handler(boolean async) {
this(null, async);
}/**
* Use the {@link Looper} for the current thread with the specified callback interface
* and set whether the handler should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages.Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}/**
* Use the provided {@link Looper} instead of the default one and take a callback
* interface in which to handle messages.Also set whether the handler
* should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages.Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param looper The looper, must not be null.
* @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
可以看到Handler的构造方法有好几个, 其实做的工作, 不外乎为他的各个成员变量赋值
mLooper
,mQueue
,mCallback
,mAsynchronous
. 分析最复杂的Handler(Callback callback, boolean async)
方法. Looper.myLooper()
方发获得了一个Looper对象, 这个Looper对象是哪里来的呢?/**
* Return the Looper object associated with the current thread.Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
查看源码看到
sThreadLocal.get()
, 原来就是从我们在Looper.prepare()
中存起来的Looper, 如果为空, 说明我们的prepare
方法根本没有执行. 抛出Can't create handler inside thread that has not called Looper.prepare()
异常. 接下来Handler的构造方法还做了一件事, 把Looper中维护的MessageQueue取出来赋值给了mQueue
字段.总结下: 获取当前线程的Looper对象取出来, 并把他和他维护的MessageQueue赋值给了Handler的成员变量.
这里有个问题:
void handleMessage(Message msg)
又是怎样被调用的呢?别急, 让我们看看Looper.loop()
方法.Looper.loop()
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
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
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}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.recycleUnchecked();
}
}
可以看到在像Handler的构造方法一样, 先获得当前线程得Looper对象. 如果为空, 那一定又是没有prepare. 接下来可以看到
for (;
;
) {}
这样一个结构, 一个死循环, 不断获取next
Message, 直到Message为空.这里有个问题: 一直在说从队列中不断取Message, Message是多久放入队列的?
Message的入队时通过
Handler
对象的sendxxx
类与postxxx
类方法实现的.- sendxxx类
//sendEmptyMessageDelayed ==>sendMessageDelayed
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
//sendMessageDelayed==>sendMessageAtTime
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);
}
可以看到最后都执行了
boolean sendMessageAtTime(Message msg, long uptimeMillis)
方法. 可以看到这里最终调用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);
}
这就时我们想要的入队操作. 值得留意的是这里的
msg.target = this
, 入队的Message标记了发送他的Handler.- postxxx方法
postxxx
方法都用两个相同的特征: 都传入Runnable
对象, 都最终调用了一个sendxxx
方法. 所以说postxxx
方法最终还是会调用enqueueMessage(queue, msg, uptimeMillis)
让消息入队. 好像有一点不对? 明明传入的一个Runnable
对象, 但是入队的时候, 存入其中却变成了Message?我们来看看其中一个postxxx
方法.
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
可以看到这里多调用了一个
getPostMessage(r)
方法. 这个方法就是将我们的Runnable
对象封装为Message对象的关键.private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
可以看到这里获得一个Message后, 将Message的callback字段设置为了Ruannable对象. 这下就豁然开朗了.
接下来接着看在MessageQueue中拥有Handler发送来的消息后, 会如何进行操作. 在死循环中.
msg.target.dispatchMessage(msg)
让msg的target(也就是发送他的Handler)去分发事件./**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
这里的逻辑就非常清晰了, 刚才想弄清楚的Handler的
handleMessage
就是再这里最后调用的. 除此之外, 消息的分发还有两条路径msg.callback
和mCallback.handleMessage(msg)
. msg.callback
还记得吗?就是postxxx
类消息发送的Runnable
对象. mCallback.handleMessage(msg)
中的mCallback则是在Handler重载的构造方法的参数. 这里一旦设置了回调,并且其handlerMessage返回值为true, 就可以实现对Hadnler的handlerMessage
的拦截.【Handler运行机制】ps: 有什么疏漏或者错误的地方还请各位指出.
参考:
- 从Handler.post(Runnable r)再一次梳理Android的消息机制(以及handler的内存泄露)
- 深入理解之 Android Handler
- <>
推荐阅读
- Fourth|Fourth season fifth episode,Chandler likes Joey‘s new girlfriend???
- Python爬虫笔记|Python爬虫学习笔记_DAY_18_Python爬虫之handler处理器的使用【Python爬虫】
- GO|GO http server (II) Server.Handler
- Laravel中schedule调度的运行机制
- Netty核心概念之ChannelHandler&Pipeline&ChannelHandlerContext
- Javascript|Javascript 运行机制
- Handler可能造成内存泄漏(四)
- Android中的消息机制(Handler)
- handler的机制和例子解析
- Android源码解惑|Thread、Handler和HandlerThread关系何在()