Handler是用来发送并处理消息的,是Android的消息机制的具体实现。一个Handler必须和一个Looper进行关联才能进行消息的发送和处理。Handler所完成的就是将一个操作从一个线程切换到与Handler关联的Looper所在的线程去执行。这个过程中,Looper扮演的是一个消息循环的角色。Looper里有一个MessageQueue,它是负责接收消息和取出消息,Handler负责的是发送消息和处理消息。默认情况下,Thread里是没有Looper的,通过ThreadLoacal可以为Thread设置Looper。下面,结合源码分别介绍ThreadLoad、Looper、MessageQueque、Handler的工作原理、以及主线程的消息循环和Handler。
ThreadLocal的工作原理
ThreadLocal是用来存取具有线程作用域的数据的类。通过其get和set方法,可以访问当前线程(调用方法的线程)中的线程本地信息。下面结合源码分析一下其具体原理
在线程的定义里面,有一个这样的成员:
ThreadLocal.Values localValues;
该成员用来存储具有线程作用域的数据。
Values是ThreadLocal里面的一个静态类:
static class Values {
它是个Hash表的数据结构,用来存储和检索数据。
采用ThreadLocal.set()存储数据
我们是通过ThreadLocal的set()方法设置Thread里面的localValues的
public void set(T value) {
Thread currentThread = Thread.currentThread();
//获取Thread的values对象
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
}
可以看看values( )的实现:
Values values(Thread current) {
return current.localValues;
}
可以看出,它的作用是获取当前线程的localValues成员,最后通过values.put( );将value保存在localValues中。
下面分析一下values.put()是如何保存数据的。
void put(ThreadLocal<?> key, Object value) {
cleanUp();
// Keep track of first tombstone. That's where we want to go back
// and add an entry if necessary.
int firstTombstone = -1;
for (int index = key.hash & mask;; index = next(index)) {
Object k = table[index];
if (k == key.reference) {
// Replace existing entry.
table[index + 1] = value;
return;
}
if (k == null) {
if (firstTombstone == -1) {
// Fill in null slot.
table[index] = key.reference;
table[index + 1] = value;
size++;
return;
}
// Go back and replace first tombstone.
table[firstTombstone] = key.reference;
table[firstTombstone + 1] = value;
tombstones--;
size++;
return;
}
// Remember first tombstone.
if (firstTombstone == -1 && k == TOMBSTONE) {
firstTombstone = index;
}
}
}
在Values类里面是用一个数组来保存数据的:
/**
* Map entries. Contains alternating keys (ThreadLocal) and values.
* The length is always a power of 2.
*/
private Object[] table;
put方法采用的hash算法在存储数据。value 存储在key的下一个位置。
采用ThreadLocal.get()获取数据
下面是get方法的实现:
public T get() {
// Optimized for the fast path.
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values != null) {
Object[] table = values.table;
int index = hash & values.mask;
if (this.reference == table[index]) {
return (T) table[index + 1];
}
} else {
values = initializeValues(currentThread);
}
return (T) values.getAfterMiss(this);
}
可以看到,根据ThreadLocal的hash值和values的掩码,计算出index,index的下一个位置就所要的值。这里采用的是hash查找算法,有兴趣的朋友可以自己查看源码。
MessageQueue的工作原理
MessageQueue不是一个队列,而是一个单链表的数据结构。通过enqueueMeassage()方法执行插入操作,通过next()执行出队操作。
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
//1. 遍历链表,将msg按when的先后顺序插入到合适的位置,或者插入到链表的末端
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;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
//2. 唤醒唤醒阻塞的next方法
nativeWake(mPtr);
}
}
return true;
}
从其实现中可以看出它主要完成以下操作
- 将msg按when的先后顺序插入到合适的位置,或者插入到链表的末端
- 唤醒阻塞的next方法
下面再看看next的工作原理:
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
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 (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (false) Log.v("MessageQueue", "Returning message: " + msg);
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf("MessageQueue", "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
可以看出,next方法是一个无限循环,如果队列里面没有消息或者消息没有到时间,就阻塞,否则,取出消息并移除。
Looper的工作原理
Looper扮演消息循环的角色,它会不停的从MessageQueue中查看是否有新消息到来,如果有就处理,如果没有就阻塞。Looper有自己的MessageQueue,在Looper被创建的时候会创建它的MessageQueue。
private Looper(boolean quitAllowed) {
//Looper的消息队列
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
它的构造方法是私有的,我们通过使用prepare()方法可以为当前线程创建Looper:
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");
}
//为当前线程创建Looper
sThreadLocal.set(new Looper(quitAllowed));
}
可以看到,Looper中,有一个ThreadLocal成员,用于存取当前线程的线程变量,prepare()方法为当前线程创建了Looper,并保存在当前线程的线程变量中。
当线程的Looper创建完毕之后,通过Looper.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
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.recycleUnchecked();
}
}
可以看到,loop方法也是一个无线循环,它会不停的从queue中取出消息,如果没有消息,则循环结束。由于next是一个阻塞方法,当队列中没有消息的时候next被阻塞,所以loop也被阻塞,当enqueueMessage()执行完毕后会唤醒next,这个时候loop也被唤醒取出消息进行分发,Looper对消息的分发是通过
msg.target.dispatchMessage(msg);
进行的,实际上是调用了Handler的dispatchMessage进行分发。关于Handler的工作原理,稍后介绍。
Handler的工作原理
Handler需要和Looper和MessageQueue进行关联才能进行工作。Handler类里有一个Looper成员和一个MessageQueue成员,分别代表与Handler关联的Looper和Looper的MessageQueue,同时还有一个aysnc标记,用于区分同步异步。Handler的主要工作是发送消息并处理消息,消息可以是同步的也可以是异步的。具体的过程是从一个线程发送消息,在与Handler关联的Looper所在的线程进行处理,从而实现了将一个操作从一个线程切换到了Handler关联的Looper所在的线程。那么,Handler是如何完成这样的切换的呢?下面将详细的讲解。
Handler和Looper关联
首先,从Handler的创建讲起。Handler提供了多个构造函数,但有两个基本的构造函数:提供Looper的和没有提供Looper的,其他的构造函数都是调用这个两个基本的构造函数进行创建的。代码如下:
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());
}
}
//获取当前线程的Looper对象,与Handler进行关联
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;
}
这是没有提供Looper的构造函数,可以看到,Handler会与创建Hanlder的线程的Looper关联,如果当前线程没有Looper,会抛出异常。所以,在创建Handler之前,一定要为当前线程创建Looper。
另外还有另外一个版本:
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
该版本主要是将Handler与指定线程的Looper相关联。
可见,Handler的构造函数主要是建立Handler与Looper进行关联。
使用Handler发送消息
在创建完Handler之后就可以通过send方式和Post方式发送消息。Handler提供了多种发送消息的方式,但有一种基本的发送方式,其他方式都是调用它来进行的。代码如下:
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);
}
可见,发送最终通过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);
}
可见最终是调用Looper的MessageQueue的enqueueMessage完成消息的发送。
Handler对消息的处理
从上面可以看到,通过Handler发送消息,最终是通过MessageQueue.enqueueMessage()添加到了Looper的消息队列里。同时,enqueueMessage()会唤醒next方法从而唤醒loop()取出消息。我们知道,loop()方法里分发消息是通过
msg.target.dispatchMessage(msg);
进行的。最终导致与message关联的Handler的dispatchMessage()被执行,而这个方法是在Looper所在的线程调用的,所以就将Handler处理消息的方法切换到了Looper所在的线程执行。
接下来看看Handler是如何处理消息的。
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {//post方式所走的路径
handleCallback(msg);
} else {//send方式所走的路径
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
条理很清晰,这里只对send方式发送的消息进行说明。在实例化Handler时,可以为其指定mCallback,在send方式发送消息是,先执行mCallback的handleMessage,如果返回true则不执行handler的handleMessage方法,否则就执行。
主线程的Looper和Handler
我们知道,ActivityThread是应用程序的主线程,而主线程的入口是其main()方法。 public static void main(String[] args) { SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
Security.addProvider(new AndroidKeyStoreProvider());
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
该方法为主线程创建了Looper和消息循环。因此,当我们在主线程里创建handler时,如果不提供Looper,默认是和主线程的Looper进行关联。
另外,ActivityThread还有两个实例变量,
final Looper mLooper = Looper.myLooper();
final H mH = new H();
其中H是一个Handler。当实例化的时候,主线程的Looper已经创建完毕,因此它是和主线程的Looper关联的。我们知道AMS是通过ApplicationThread和应用程序通讯来完成应用程序组件的生命周期回调,而这两者之间的通讯是跨进程的。其中,ApplicationThread是服务方,AMS通过Binder使用ApplicationThread。而ApplicationThread的Binder方法运行在线程池中,组件的生命周期是运行在主线程,因此通过H来进行切换。