在这篇文章开始前,我们先总结一下前两篇文章中关于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) {
-
- 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;
- prev.next = msg;
- }
-
- ...
- }
上面是入队列的关键代码,而其所做的操作无非就是根据 when 字段,将消息插入队列中的合适位置。既然消息已经放到队列中去了,那么下一步就是在Looper的轮循操作中去获取消息,然后将消息进行分发。我们可以在Looper 的loop方法中看到其调用了MessageQueue的next方法。
- for (;;) {
- Message msg = queue.next();
- if (msg == null) {
-
- return;
- }
-
-
- 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;
- int nextPollTimeoutMillis = 0;
- for (;;) {
- if (nextPollTimeoutMillis != 0) {
- Binder.flushPendingCommands();
- }
-
-
-
- nativePollOnce(mPtr, nextPollTimeoutMillis);
-
- synchronized (this) {
-
- final long now = SystemClock.uptimeMillis();
- Message prevMsg = null;
- Message msg = mMessages;
- if (msg != null && msg.target == null) {
-
- do {
- prevMsg = msg;
- msg = msg.next;
- } while (msg != null && !msg.isAsynchronous());
- }
- if (msg != null) {
- if (now < msg.when) {
-
- nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
- } else {
-
- 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 {
-
- nextPollTimeoutMillis = -1;
- }
-
-
- if (mQuitting) {
- dispose();
- return null;
- }
-
-
-
-
- if (pendingIdleHandlerCount < 0
- && (mMessages == null || now < mMessages.when)) {
- pendingIdleHandlerCount = mIdleHandlers.size();
- }
- if (pendingIdleHandlerCount <= 0) {
-
- mBlocked = true;
- continue;
- }
-
- if (mPendingIdleHandlers == null) {
- mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
- }
- mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
- }
-
-
-
- for (int i = 0; i < pendingIdleHandlerCount; i++) {
- final IdleHandler idler = mPendingIdleHandlers[i];
- mPendingIdleHandlers[i] = null;
-
- boolean keep = false;
- try {
- keep = idler.queueIdle();
- } catch (Throwable t) {
- Log.wtf("MessageQueue", "IdleHandler threw exception", t);
- }
-
- if (!keep) {
- synchronized (this) {
- mIdleHandlers.remove(idler);
- }
- }
- }
-
-
- pendingIdleHandlerCount = 0;
-
-
-
- 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类中,我们可以看到
还有其构造函数:
- 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;
- message.sendToTarget();
-
- 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的流转过程,应该有一个清楚的了解了吧。 0 0