根据源码注释说明, handler设计目的如下:
There are two main uses for a Handler: (1) to schedule messages and
runnables to be executed as some point in the future; and (2) to enqueue
an action to be performed on a different thread than your own.
Handler有两个主要用途:
1. 把 Message 和 Runnable 安排在未来的某个时间点执行;
2. 把某些操作放入其他的线程中执行.
注意, Handler 只是发送消息的一个工具, 并不是使用 Thread 所必须的.
具体机制
-
Handler 初始化: 初始时会获取当前
Thread
的Looper
, 其中 android 主线程会自动初始化一个Looper
, 而自己创建的线程则需要自己维护Looper
(通过Looper.prepare
创建, 通过Looper.loop
开启处理message
的循环 ).public Handler(Callback callback, boolean async) { mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; // 获取对应线程的Looper的MessageQueue mCallback = callback; mAsynchronous = async; }
-
Handler发送消息:
Handler
发送消息是把Message
发送给Looper
内的MessageQueue
, 所有类型的消息发送到最后都是调用的enqueueMessage
. 而handler.enqueueMessage
则是调用的MessageQueue.enqueueMessage
// Handler.enqueueMessage private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
// MessageQueue.enqueueMessage 省略了部分代码 boolean enqueueMessage(Message msg, long when) { synchronized (this) { if (mQuitting) { msg.recycle(); return false; } msg.when = when; Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) { // 如果当前队列为空/已阻塞, 则唤醒 msg.next = p; mMessages = msg; needWake = mBlocked; } else { // 没有阻塞, 把新消息放入消息队列中(链表) 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; } if (needWake) { nativeWake(mPtr); } } return true; }
-
处理消息:
Looper
中会死循环查找MessageQueue
, 如果next Message != null
, 那么这个message
就会交给它内部的target Handler
处理 (msg.target.dispatchMessage(msg)
) ;// 省略了部分代码, 仅保留逻辑部分 public static void loop() { final Looper me = myLooper(); final MessageQueue queue = me.mQueue; for (;;) { Message msg = queue.next(); // 可能阻塞 if (msg == null) { return; } msg.target.dispatchMessage(msg); msg.recycleUnchecked(); // 清空 } }
/** * 由此可知, 如果message中包含runnable, 或者Handler实例化时传入了callback, * 那么handler子类重写的handleMessage就不会执行了. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { // 调用 Message 内部的 Runnable callback handleCallback(msg); } else { if (mCallback != null) { // 使用构造方法中传入的Handler内部的Callback接口 if (mCallback.handleMessage(msg)) { return; } } // 或者使用子类的处理方式 handleMessage(msg); } }
新建Thread的两种方式
第一种:
new Thread(new Runnable() {
@Override
public void run() {
Log.i("TAG", "run on Runnable");
}
}) {
@Override
public void run() {
super.run();
Log.i("TAG", "run on Thread");
}
}.start();
这种创建方式线程在执行完代码后( 先执行 Thread.run, Runnable 的 run 执行在 Thread.run 的 super 里面 )就结束了.
第二种:
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Log.i("TAG", "run on Runnable");
Looper.loop();
}
}).start();
这种方式开启了死循环, Thread 会一直存活下去. 可以命名此 Thread, 使用 getLooper().quit 来销毁.
HandlerThread
这个类继承自Thread,并在内部start时自动创建出Looper循环,所以可以使用new Handler(HandlerThread.getLooper())
的方式很方便的去关联一个Handler,在循环开启一个较长时间存活的子线程时可以使用。如果不再需要时,可以通过HandlerThread.quitSafely
去退出该线程。
Handler的bug
在使用Handler去循环发送消息时容易出现丢失消息的问题,例如多次在接收到消息时再次延迟发送一个消息时最容易出现,这种场景下就不要使用Handler的方式去处理了,可以直接在Thread.run中添加sleep处理。