一 前言
对于开发者来说,Android的消息机制离不开Handler,下面我们看看官网对Handler的解释:
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
上面这段话,说的比较简单,意思大概就是Handler用来向一个线程的消息队列中发送和处理消息的。而且每一个Handler实例都和一个线程/消息队列相关联。当开发者在一个线程创建一个Handler时,该Handler就会被绑定到该线程及该线程创建的消息队列(消息队列通过线程的Looper创建),然后发送和读取消息。
Android的消息机制源码实现主要包括四个概念:
- Looper——用来创建消息队列;
- MessageQueue——发送和读取消息;
- Handler——对于开发者而言,封装了MessageQueue的发送和读取消息;
- Message——消息格式;
二 Handler消息机制的相关源码
主要分析Looper,Handler两个类。
2.1 Looper
先看looper类中的注释,说明了Handler的使用方法。
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
//1
Looper.prepare();
//2
mHandler = new Handler() {
public void handleMessage(Message msg) {
//
}
};
//
Looper.loop();
}
public final class Looper {
private static final String TAG = "Looper";
//ThreadLocal--线程本地存储,是用来存储线程的数据,但针对一个线程而言,只会读取自己线程的数据。
ThreadLocal<Looper>用来存储自己线程的Looper。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
private Printer mLogging;
private long mTraceTag;
private long mSlowDispatchThresholdMs;
// a.非UI线程初始化Looper
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
//quitAllowed表示允许退出,默认是true
if (sThreadLocal.get() != null) {
//对于一个线程,在Looper未初始化之前,如果ThreadLocal获取的数据不为空,会抛出异常,因为一个线程只对应一个Looper
throw new RuntimeException("Only one Looper may be created per thread");
}
//初始化Looper,并将Looper存储下来。
sThreadLocal.set(new Looper(quitAllowed));
}
// b.UI线程初始化Looper
// 对于Activity线程(UI线程)比较特殊,他会在创建时,就会创建一个Looper,无需再使用perpare创建。
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
/**
* Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
//Looper开启循环,读取队列中
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 (;;) {
//读取MessageQueue的下一条消息
Message msg = queue.next(); // 可能阻塞
if (msg == null) {
//无消息则退出循环
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 slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
final long end;
try {
//分发Message
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (slowDispatchThresholdMs > 0) {
final long time = end - start;
if (time > slowDispatchThresholdMs) {
Slog.w(TAG, "Dispatch took " + time + "ms on "
+ Thread.currentThread().getName() + ", h=" +
msg.target + " cb=" + msg.callback + " msg=" + msg.what);
}
}
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();
}
}
//从ThreadLocal获取已经存储的Looper对象
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
/**
* Return the {@link MessageQueue} object associated with the current
* thread. This must be called from a thread running a Looper, or a
* NullPointerException will be thrown.
*/
public static @NonNull MessageQueue myQueue() {
return myLooper().mQueue;
}
//初始化Looper
private Looper(boolean quitAllowed) {
//创建消息队列
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
/**
* Returns true if the current thread is this looper's thread.
*/
public boolean isCurrentThread() {
return Thread.currentThread() == mThread;
}
public void setMessageLogging(@Nullable Printer printer) {
mLogging = printer;
}
/** {@hide} */
public void setTraceTag(long traceTag) {
mTraceTag = traceTag;
}
/** {@hide} */
public void setSlowDispatchThresholdMs(long slowDispatchThresholdMs) {
mSlowDispatchThresholdMs = slowDispatchThresholdMs;
}
public void quit() {
mQueue.quit(false);
}
public void quitSafely() {
mQueue.quit(true);
}
/**
* Gets the Thread associated with this Looper.
*
* @return The looper's thread.
*/
public @NonNull Thread getThread() {
return mThread;
}
public @NonNull MessageQueue getQueue() {
return mQueue;
}
......
}
2.2 Handler
public class Handler {
private static final boolean FIND_POTENTIAL_LEAKS = false;
private static final String TAG = "Handler";
private static Handler MAIN_THREAD_HANDLER = null;
public interface Callback {
public boolean handleMessage(Message msg);
}
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
/**
* 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);
}
}
// d1. 创建Handler对象
public Handler() {
this(null, false);
}
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
public Handler(boolean async) {
this(null, async);
}
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());
}
}
//d2.由于已经执行了Looper.prepare(),所以从ThreadLocal获取Looper对象;
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//d3.获取Looper类初始化时,创建的MessageQueue对象
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
/** @hide */
@NonNull
public static Handler getMain() {
if (MAIN_THREAD_HANDLER == null) {
MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper());
}
return MAIN_THREAD_HANDLER;
}
/** @hide */
@NonNull
public static Handler mainIfNull(@Nullable Handler handler) {
return handler == null ? getMain() : handler;
}
/** {@hide} */
public String getTraceName(Message message) {
final StringBuilder sb = new StringBuilder();
sb.append(getClass().getName()).append(": ");
if (message.callback != null) {
sb.append(message.callback.getClass().getName());
} else {
sb.append("#").append(message.what);
}
return sb.toString();
}
public String getMessageName(Message message) {
if (message.callback != null) {
return message.callback.getClass().getName();
}
return "0x" + Integer.toHexString(message.what);
}
public final Message obtainMessage()
{
return Message.obtain(this);
}
public final Message obtainMessage(int what)
{
return Message.obtain(this, what);
}
public final Message obtainMessage(int what, Object obj)
{
return Message.obtain(this, what, obj);
}
public final Message obtainMessage(int what, int arg1, int arg2)
{
return Message.obtain(this, what, arg1, arg2);
}
public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
{
return Message.obtain(this, what, arg1, arg2, obj);
}
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean postAtTime(Runnable r, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
public final boolean postAtFrontOfQueue(Runnable r)
{
return sendMessageAtFrontOfQueue(getPostMessage(r));
}
public final boolean runWithScissors(final Runnable r, long timeout) {
if (r == null) {
throw new IllegalArgumentException("runnable must not be null");
}
if (timeout < 0) {
throw new IllegalArgumentException("timeout must be non-negative");
}
if (Looper.myLooper() == mLooper) {
r.run();
return true;
}
BlockingRunnable br = new BlockingRunnable(r);
return br.postAndWait(this, timeout);
}
/**
* Remove any pending posts of Runnable r that are in the message queue.
*/
public final void removeCallbacks(Runnable r)
{
mQueue.removeMessages(this, r, null);
}
/**
* Remove any pending posts of Runnable <var>r</var> with Object
* <var>token</var> that are in the message queue. If <var>token</var> is null,
* all callbacks will be removed.
*/
public final void removeCallbacks(Runnable r, Object token)
{
mQueue.removeMessages(this, r, token);
}
//e1.handler发送消息
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
//e2.延迟发送消息
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//e3.定时发送消息
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);
}
public final boolean sendMessageAtFrontOfQueue(Message msg) {
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, 0);
}
//e4.真正发送消息的方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//把当前Handler复制给Message的taget属性
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
public final void removeMessages(int what) {
mQueue.removeMessages(this, what, null);
}
public final void removeMessages(int what, Object object) {
mQueue.removeMessages(this, what, object);
}
public final void removeCallbacksAndMessages(Object token) {
mQueue.removeCallbacksAndMessages(this, token);
}
/**
* Check if there are any pending posts of messages with code 'what' in
* the message queue.
*/
public final boolean hasMessages(int what) {
return mQueue.hasMessages(this, what, null);
}
/**
* Return whether there are any messages or callbacks currently scheduled on this handler.
* @hide
*/
public final boolean hasMessagesOrCallbacks() {
return mQueue.hasMessages(this);
}
public final boolean hasCallbacks(Runnable r) {
return mQueue.hasMessages(this, r, null);
}
public final Looper getLooper() {
return mLooper;
}
private static Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain();
m.obj = token;
m.callback = r;
return m;
}
private static void handleCallback(Message message) {
message.callback.run();
}
.......
}
三 Handler源码分析总结
根据源码画一张两个非UI线程之间Handler通信流程图,如下图:

主要下面几个步骤:
*创建一个消息队列: 启动一个非UI线程(下面叫线程1),在线程里面调用Looper.prepare方法,创建一个Looper对象,每一个线程都会对应一个自己的Looper对象,同时Looper对象内部会创建一个消息队列;
- 关联Handler与消息队里:在线程1中创建实例化一个Handler对象,该Hander内部会从ThreadLocal获取上一步创建的Looper对象和MessageQueue对象,这样Handler就和消息队列关联起来了;
- 创建一个Message对象:接着启动一个新的子线程(叫线程2),在线程2中首先创建一个Message对象,注意这是的Message的target还是空的;
- 发送消息:继续在线程2中调用handler.sendMessage方法发送消息,该方法内部最终调用了MessageQueue(这个messagequeue对象就是之前Looper创建,并在实例化Handler时,传给了handler)的enqueueMessage方法;
- 读取消息:在线程1中调用Looper.loop循环读取线程2中发送到消息队列的数据;
- 分发消息:调用handler的dispathcMessage分发消息给对应的handler;
- 处理消息:Handler处理消息;
Android提供了个HandlerThread类就是一个结合了Handler的非UI线程
源码如下:
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
private @Nullable Handler mHandler;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
......
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
//1
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
//2
Looper.loop();
mTid = -1;
}
....
}
上面源码的流程,和我们之前说的非UI线程创建消息队列的逻辑一模一样,就不在说了。
注意,在ActivityTherad线程启动时,会自动执行Looper.prepare()和Looper.loop()方法,所以开发者不需要在执行这两个方法。
由于本人能力有限,有的方面理解不当,后续会根据情况继续调整。
网友评论