在Android中,当要更新ui的时候,咱们必需要在主线程中进行更新,缘由时当主线程被阻塞了5s以上就会出现anr异常,会致使程序崩溃。因此一些耗时的操做必需要放在子线程中,可是在子线程中又不能作更新ui的操做,因此为了解决这个问题,Android设计了handler机制,handler的出现创建起了主线程与子进程之间的通讯桥梁,使得ui更新问题获得改善,下面就来剖析一下handler。ActivityThread启动了应用程序的主线程,在ActivityThread的main方法中:java
public static final void main(String[] args) { SamplingProfilerIntegration.start(); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); if (sMainThreadHandler == null) { sMainThreadHandler = new Handler(); } ActivityThread thread = new ActivityThread(); thread.attach(false); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); ...... }
从上述代码能够看出,首先要执行Looper.prepareMainLooper();操做,而后进入loop进行循环。在prepareMainLooper中,调用prepare方法使用sThreadLocal给当前线程设置一个Looper,若是当前线程中没有,就初始化一个Looper,在Looper的构造方法中顺便建立了一个MessageQueue。细心的读者可能会注意到prepareMainLooper和prepare方法都是static的,sThreadLocal也是个静态变量,首先不考虑子线程存在的状况,只考虑主线程,因此不管咱们在应用程序的哪一个地方调用Looper.prepareMainLooper();经过sThreadLocal.get()获得的都是同一个looper对象,这样就能够保证一个线程中只有一个Looper对象,那么也就意味着一个线程中只有一个MessageQueue。web
public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } } 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)); } private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
执行完 Looper.prepareMainLooper()以后,就是开始Looper.loop()进行消息的循环读取而且进行分发,这个稍后分析完Handler后再分析。async
下面咱们再分析一下Handler。
在代码中咱们常常的这样用:ide
private Handler handler = new Handler(){ public void handleMessage(Message msg) { // process incoming messages here } } 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; mCallback = callback; mAsynchronous = async; }
在Handler的构造方法中,经过Looper.myLooper()获取本线程中惟一的一个Looper对象,而且初始化hanlder中的消息队列,这个消息队列和Looper中的一开始初始化的消息队列是同一个。
当调用handler.sendMessage或者sendEmpty方法时,最终要走的方法都是sendMessageAtTime方法:svg
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); }
在enqueueMessage方法中,给当前要加入消息队列的msg设置一个target为this,这个this也就是当前的handler对象,主要是为了后面的looper循环出消息后,方便知道这个msg向何处分发,该由哪一个handler进行处理。接着就调用MessageQueue的enqueueMessage方法将msg加入队列中。oop
boolean enqueueMessage(Message msg, long when) { ...... synchronized (this) { ...... 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 { 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; }
当消息对列中没有任何msg的时候,当前加入的msg就应该是队列的队头,而且从else语句咱们能够看出,整个消息对列是个循环对列。此时消息对列中已经有了msg,那么这个msg应该被接受并进行分发处理,在ActivityThread中调用了Looper.loop()方法进行消息的轮询。ui
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) { return; } Printer logging = me.mLogging; ....... msg.target.dispatchMessage(msg); final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { } msg.recycle(); } }
其中的for循环为死循环,有人可能纳闷了,looper.loop()是运行在主线程中的,而其中有是个死循环,不是说好的主线程中不能作超时的操做吗?呵呵,由于在循环中轮询消息队列中的消息时候,若是没有消息,则会被阻塞。因此这里不用担忧anr的问题。经过queue.next()获取出msg后,经过msg.target.dispatchMessage(msg)处理这个消息,这个msg.target就是要处理消息的handle,这也就是为啥在handler中要重写dispatchMessage方法的缘由。最后调用recycle释放消息,之因此要recycle一下,是由于Message能够不用new的方式,也能够经过Message.obtain方法从消息池中获取一个,由于消息池中的消息个数有限,若是用完消息后,不及时的recycle的 话,就会形成msg对象不能重复利用。this
接下来具体的分析下queue.next()这个方法,在注释中咱们看到,这个方法有可能会被阻塞,阻塞的缘由是消息队列中没有消息。spa
Message next() { int pendingIdleHandlerCount = -1; // -1 only during first iteration int nextPollTimeoutMillis = 0; for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } // We can assume mPtr != 0 because the loop is obviously still running. // The looper will not call this method after the loop quits. nativePollOnce(mPtr, 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); msg.markInUse(); 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; } }
nativePollOnce(mPtr, nextPollTimeoutMillis)当轮询没有消息时,会进行阻塞。消息唤醒和阻塞机制将会在下一篇文章进行介绍,请你们关注。.net
最后对Handler作一下总结。从消息的分发一直到消息的处理,前后接触到的几个名词有Looper、MessageQueue、Thread、Handler、Message。
消息处理机制大概的一个处理过程以下:
关于轮询的时候,阻塞和唤醒机制请看下一篇文章。
从源码角度分析native层消息机制与java层消息机制的关联
补充:在子线程中要更新ui的时候,能够这样处理
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();
}
}