首页 > 代码库 > Android中利用Handler实现消息的分发机制(二)
Android中利用Handler实现消息的分发机制(二)
在这篇文章开始前,我们先总结一下前两篇文章中关于Handler, Looper和MessageQueue等的一些关键点:
0)在线程中创建Handler之前,必须先调用Looper.prepare(), 创建一个线程局部变量Looper,然后调用Looper.loop() 进入轮循。
1)当Handler创建之后,就可以调用Handler的sendMessageAtTime方法发送消息,而实际上是调用MessageQueue的enqueueMessage方法,将对应的消息放入消息队列。
2)每一个线程都只有一个Looper,这个Looper负责对MessageQueue进行轮循,当获取到Message,就调用handler.dispatchMessage进行分发。
从上面这三点,我们就可以大概地看出Handler的使用流程了。
今天我们就先从消息开始的地方讲起,就是Handler的 enqueueMessage 方法了,代码如下:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
此方法主要做了两件事:
1)将msg.target 设置成当前Handler对象
2)调用MessageQueue的enqueueMessage方法
所以,其实就是在这里,将Message对象放到消息队列中去的。
说到MessageQueue,我们首先要明白这个消息队列其实是一个链表的结构,一个串一个的。
而其队列的初始化并不是在 java层做的,而是在JNI层利用C++实现的。
我们可以看看其定义的几个native方法,如下:
private native static long nativeInit(); private native static void nativeDestroy(long ptr); private native static void nativePollOnce(long ptr, int timeoutMillis); private native static void nativeWake(long ptr); private native static boolean nativeIsIdling(long ptr);
而其构造函数如下:
MessageQueue(boolean quitAllowed) { mQuitAllowed = quitAllowed; mPtr = nativeInit(); }
在这里,我们并不进入其在JNI层的代码,水太深了。
我们还是从Java层来看吧。在MessageEnqueue的 enqueueMesage方法中,主要的代码如下:
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 { // 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; 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; } ... }
既然消息已经放到队列中去了,那么下一步就是在Looper的轮循操作中去获取消息,然后将消息进行分发。我们可以在Looper 的loop方法中看到其调用了MessageQueue的next方法。
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);
那么很显然,就是在MessageQueue的next方法中,获取消息了,让我们也进去其方法看一下吧。
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; } }
1)是一个 for(;;)循环
2)只有当获取 message的时候或者mQuitting为true的时候才会跳出循环。
3)在获取消息的时候,会根据 Message.when 字段来进行判断
从以上几点,我们就可以大概了解为什么说在 loop方法中,next方法有可能会阻塞,因为它就是一个无限的轮循操作呀。
好吧,到这里之后,我们大概知道了以下两件事情:
1)在Handler的sendMessageAtTime方法调用MessageQueue的 enqueueMessage方法,将消息放入队列。
2)在Looper的looop方法,调用MessageQueue的next方法,将消息取出队列。
接下来第三步,很显然,就是调用handler的dispatchMessage方法了,如下:
msg.target.dispatchMessage(msg);
在文章的一开始,我们就注意到了msg.target 正好就是 handler对象,于是逻辑又来到了Handler的dispatchMessage方法,如下:
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
从代码的逻辑来看,我们需要了解一下几个变量方法都是要什么了:
1)msg.callback
2) mCallback
3 ) handleMessage
首先, msg.callback是什么?
在Message类中,我们可以看到
Runnable callback;
还有其构造函数:
public static Message obtain(Handler h, Runnable callback) { Message m = obtain(); m.target = h; m.callback = callback; return m; }
其实就是一个Runnable变量,可以放到一个新的线程中去跑,可以在获取Message的时候自定义设置。
所以在dispatchMessage中,首先就是判断是否有对Message设置了Runnable的callback,如果有,就执行这个callback方法,如下:
private static void handleCallback(Message message) { message.callback.run(); }
那么,第二个mCallback又是什么呢,它其实上是Handler内置的一个接口,如下:
public interface Callback { public boolean handleMessage(Message msg); }
如果有我们的 Handler有实现这个接口,那么当分发消息的时候,此接口就会优先处理消息。
而一般情况下,只有我们想去继承Handler类,实现自定义的Handler的时候,我们才会去实现这个接口,而当此接口返回true的时候,Handler默认的handleMessage方法就不会再被调用了。反之,则依然会调用。
最后,就是我们最普通的handleMessage方法了,也就是我们在实现一个最普通的handler的时候所实现的方法了。
同样,没有例子怎么可以呢,请看代码:
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { Log.v("Test", "Id of LooperThread : " + Thread.currentThread().getId()); switch (msg.what) { case MSG_ID_1: Log.v("Test", "Toast called from Handler.sendMessage()"); break; case MSG_ID_2: String str = (String) msg.obj; Log.v("Test", str); break; } } }; Looper.loop(); } } protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.v("Test", "Id of MainThread : " + Thread.currentThread().getId()); LooperThread looperThread = new LooperThread(); looperThread.start(); while(looperThread.mHandler == null){ } Message message = Message.obtain(looperThread.mHandler, new Runnable() { @Override public void run() { Log.v("Test", "Message.callack()"); } }); message.what = MSG_ID_1; looperThread.mHandler.sendMessage(message); looperThread.mHandler.post(new Runnable() { @Override public void run() { Log.v("Test", "Handler.callack()"); } }); }
在这里,我们利用Message.obtain(Handler, Runnable) 方法和Handler.post方法来构造和发送消息,得到的结果如下:
10-28 11:27:49.328: V/Test(22009): Id of MainThread : 1 10-28 11:27:49.328: V/Test(22009): Message.callack() 10-28 11:27:49.328: V/Test(22009): Handler.callack()
好了,这篇文章就到此结束,相信大家对整个Message的流转过程,应该有一个清楚的了解了吧。
Android中利用Handler实现消息的分发机制(二)