Android(安卓)Handler机制5--消息发送
移步Android Handler机制详解
- 1、Handler发送消息
- 2、Handler的send方案
- 3、Handler的post方案
1 Handler发送消息
send方案.pngpost方案.png
- send方案发送消息(需要回调才能接收消息)
- sendMessage(Message) 立即发送Message到消息队列
- sendMessageAtFrontOfQueue(Message) 立即发送Message到队列,而且是放在队列的最前面
- sendMessageAtTime(Message,long) 设置时间,发送Message到队列
- sendMessageDelayed(Message,long) 延时若干毫秒后,发送Message到队列
- post方案 立即发送Message到消息队列
- post(Runnable) 立即发送Message到消息队列
- postAtFrontOfQueue(Runnable) 立即发送Message到队列,而且是放在队列的最前面
- postAtTime(Runnable,long) 设置时间,发送Message到队列
- postDelayed(Runnable,long) 在延时若干毫秒后,发送Message到队列
2 Handler的send方案
以Handler的sendMessage(Message msg)为例子
2.1 sendMessage(Message msg)方法
代码在Handler.java 505行
/** * Pushes a message onto the end of the message queue after all pending messages * before the current time. It will be received in {@link #handleMessage}, * in the thread attached to this handler. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); }
- 在当前时间,在所有待处理消息之后,将消息推送到消息队列的末尾。在和当前线程关联的的Handler里面的handleMessage将收到这条消息
2.1.1 boolean sendMessageDelayed(Message msg, long delayMillis)
代码在Handler.java 565行
/** * Enqueue a message into the message queue after all pending messages * before (current time + delayMillis). You will receive it in * {@link #handleMessage}, in the thread attached to this handler. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that a * result of true does not mean the message will be processed -- if * the looper is quit before the delivery time of the message * occurs then the message will be dropped. */ public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }
该方法内部就做了两件事
- 1、判断delayMillis是否小于0
- 2、调用了public boolean sendMessageAtTime(Message msg, long uptimeMillis)方法
2.1.2 boolean sendMessageAtTime(Message msg, long uptimeMillis)
代码在Handler.java 592行
/** * Enqueue a message into the message queue after all pending messages * before the absolute time (in milliseconds) uptimeMillis. * The time-base is {@link android.os.SystemClock#uptimeMillis}. * Time spent in deep sleep will add an additional delay to execution. * You will receive it in {@link #handleMessage}, in the thread attached * to this handler. * * @param uptimeMillis The absolute time at which the message should be * delivered, using the * {@link android.os.SystemClock#uptimeMillis} time-base. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that a * result of true does not mean the message will be processed -- if * the looper is quit before the delivery time of the message * occurs then the message will be dropped. */ 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); }
- 以android系统的SystemClock的uptimeMillis()为基准,以毫秒为基本单位的绝对时间下,在所有待处理消息后,将消息放到消息队列中。
- 深度睡眠中的时间将会延迟执行的时间,你将在和当前线程办的规定的Handler中的handleMessage中收到该消息。
- 因为通常我们理解的异步是指新开一个线程,但是这里不是,因为异步的也是发送到looper所绑定的消息队列中,这里的异步主要是针对Message中的障栅(Barrier)而言的,当出现障栅(Barrier)的时候,同步的会被阻塞,而异步的则不会。所以这个异步仅仅是一个标记而已。
该方法内部就做了两件事
- 1、获取消息队列,并对该消息队列做非空判断,如果为null,直接返回false,表示消息发送失败
- 2、调用了boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)方法
2.1.3 boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
代码在Handler.java 626行
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
本方法内部做了三件事
- 设置msg的target变量,并将target指向自己
- 如果Handler的mAsynchronous值为true(默认为false,即不设置),则设置msg的flags值,让是否异步在Handler和Message达成统一。
- 调用MessageQueue的enqueueMessage()方法
2.1.4 boolean enqueueMessage(Message msg, long when)方法
代码在MessageQueue.java 533行
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(TAG, e.getMessage(), e); msg.recycle(); return false; } // 第五步 msg.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; // 第六步 //根据when的比较来判断要添加的Message是否应该放在队列头部,当第一个添加消息的时候, // 测试队列为空,所以该Message也应该位于头部。 if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. // 把msg的下一个元素设置为p msg.next = p; // 把msg设置为链表的头部元素 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. //除非消息队列的头部是障栅(barrier),或者消息队列的第一个消息是异步消息, //否则如果是插入到中间位置,我们通常不唤醒消息队列, // 第八步 needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; // 第九步 // 不断遍历消息队列,根据when的比较找到合适的插入Message的位置。 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) { nativeWake(mPtr); } } // 第十四步 return true; }
- 第1步骤、 判断msg的target变量是否为null,如果为null,则为障栅(barrier),而障栅(barrier)入队则是通过postSyncBarrier()方法入队,所以msg的target一定有值
- 第2步骤、 判断msg的标志位,因为此时的msg应该是要入队,意味着msg的标志位应该显示还未被使用。如果显示已使用,明显有问题,直接抛异常。
- 第3步骤、 加入同步锁。
- 第4步骤、 判断消息队列是否正在被关闭,如果是正在被关闭,则return false告诉消息入队是失败,并且回收消息
- 第5步骤、 设置msg的when并且修改msg的标志位,msg标志位显示为已使用
- 第6步骤、 如果p==null则说明消息队列中的链表的头部元素为null;when == 0 表示立即执行;when< p.when 表示 msg的执行时间早与链表中的头部元素的时间,所以上面三个条件,那个条件成立,都要把msg设置成消息队列中链表的头部是元素
- 第7步骤、 如果上面三个条件都不满足则说明要把msg插入到中间的位置,不需要插入到头部
- 第8步骤、 如果头部元素不是障栅(barrier)或者异步消息,而且还是插入中间的位置,我们是不唤醒消息队列的。
- 第9步骤、 进入一个死循环,将p的值赋值给prev,前面的带我们知道,p指向的是mMessage,所以这里是将prev指向了mMessage,在下一次循环的时候,prev则指向了第一个message,一次类推。接着讲p指向了p.next也就是mMessage.next,也就是消息队列链表中的第二个元素。这一步骤实现了消息指针的移动,此时p表示的消息队列中第二个元素。
- 第10步骤、 p==null,则说明没有下一个元素,即消息队列到头了,跳出循环;p!=null&&when < p.when 则说明当前需要入队的这个message的执行时间是小于队列中这个任务的执行时间的,也就是说这个需要入队的message需要比队列中这个message先执行,则说明这个位置刚刚是适合这个message的,所以跳出循环。 如果上面的两个条件都不满足,则说明这个位置还不是放置这个需要入队的message,则继续跟链表中后面的元素,也就是继续跟消息队列中的下一个消息进行对比,直到满足条件或者到达队列的末尾。
- 第11步骤、 因为没有满足条件,说明队列中还有消息,不需要唤醒。
- 第12步骤、 跳出循环后主要做了两件事:事件A,将入队的这个消息的next指向循环中获取到的应该排在这个消息之后message。事件B,将msg前面的message.next指向了msg。这样就将一个message完成了入队。
- 第13步骤、 如果需要唤醒,则唤醒,具体请看后面的Handler中的Native详解。
- 第14步骤、 返回true,告知入队成功。
插入消息后,有条件地执行nativeWake去唤醒epoll。needWake的值依赖mBlocked——当进入next()方法时没有待处理的消息,mBlock为true,有消息并返回到looper时,mBlock为false。
结合next()和enqueueMessage()方法,得知nativeWake被调用的条件为:
- next()方法在等待新消息,且新插入消息的为链表头时。needWake为true
- 设置了Sync Barrier,且插入的消息是“异步”的。needWake为true
2.2 boolean sendMessageAtFrontOfQueue(Message msg)
代码在Handler.java 615行
/** * Enqueue a message at the front of the message queue, to be processed on * the next iteration of the message loop. You will receive it in * {@link #handleMessage}, in the thread attached to this handler. * This method is only for use in very special circumstances -- it * can easily starve the message queue, cause ordering problems, or have * other unexpected side-effects. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ 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); }
- 在消息队列的最前面插入一个消息,在消息循环的下一次迭代中进行处理。
- 由于它可以轻松的解决消息队列的排序问题和其他的意外副作用。
方法内部的实现和boolean sendMessageAtTime(Message msg, long uptimeMillis)大体上一致,唯一的区别就是该方法在调用enqueueMessage(MessageQueue, Message, long)方法的时候,最后一个参数是0而已。
2.3 boolean sendEmptyMessage(int what)
代码在Handler.java 517行
/** * Sends a Message containing only the what value. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0); }
发送一个仅有what的Message
boolean sendEmptyMessageDelayed(int what, long delayMillis)
代码在Handler.java 531行
/** * Sends a Message containing only the what value, to be delivered * after the specified amount of time elapses. * @see #sendMessageDelayed(android.os.Message, long) * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); }
- 发送一个仅有what的Message,并且延迟特定的时间发送
- 这个方法内部主要就是做了3件事
1、调用Message.obtain();从消息对象池中获取一个空的Message。
2、设置这个Message的what值
3、调用sendMessageDelayed(Message,long) 将这个消息方法
2.4 boolean sendEmptyMessageAtTime(int what, long uptimeMillis)
代码在Handler.java 547行
/** * Sends a Message containing only the what value, to be delivered * at a specific time. * @see #sendMessageAtTime(android.os.Message, long) * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageAtTime(msg, uptimeMillis); }
- 发送一个仅有what的Message,并且在特定的时间发送
- 这个方法内部主要就是做了3件事
- 1、调用Message.obtain();从消息对象池中获取一个空的Message。
- 2、设置这个Message的what值
- 3、调用sendMessageAtTime(Message,long) 将这个消息方法
2.5 小结
这些send方案都会从这里或者那里最终走到boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
5713484-e56c82c4e36768f5.png
3 Handler的post方案
3.1 boolean post(Runnable r)方法
代码在Handler.java 324行
/** * Causes the Runnable r to be added to the message queue. * The runnable will be run on the thread to which this handler is * attached. * * @param r The Runnable that will be executed. * * @return Returns true if the Runnable was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); }
将一个Runnable添加到消息队列中,这个runnable将会在和当前Handler关联的线程中被执行。
就是调用了sendMessageDelayed(Message, long);这个方法,所以可见boolean post(Runnable r)这个方法最终还是走到上面说到的send的流程中
最终调用boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)。
3.1.1 Message getPostMessage(Runnable r)方法
代码在Handler.java 725行
private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
代码很简单,主要是做了两件事
- 通过Message.obtain()从消息对象池中获取一个空的Message
- 将这空的Message的callback变量指向Runnable
最后返回这个Message m。
3.1.2 小结
- boolean post(Runnable r)方法的内置也是通过Message.obtain()来获取一个Message对象m,然后仅仅把m的callback指向参数r而已。
- 最后最终通过调用send方案的某个流程最终调用到boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
3.2 boolean postAtTime(Runnable r, long uptimeMillis)方法
代码在Handler.java 347行
/** * Causes the Runnable r to be added to the message queue, to be run * at a specific time given by uptimeMillis. * The time-base is {@link android.os.SystemClock#uptimeMillis}. * Time spent in deep sleep will add an additional delay to execution. * The runnable will be run on the thread to which this handler is attached. * * @param r The Runnable that will be executed. * @param uptimeMillis The absolute time at which the callback should run, * using the {@link android.os.SystemClock#uptimeMillis} time-base. * * @return Returns true if the Runnable was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that a * result of true does not mean the Runnable will be processed -- if * the looper is quit before the delivery time of the message * occurs then the message will be dropped. */ public final boolean postAtTime(Runnable r, long uptimeMillis) { return sendMessageAtTime(getPostMessage(r), uptimeMillis); }
- 将一个Runnable添加到消息队列中,这个runnable将会一个特定的时间被执行,这个时间是以android.os.SystemClock.uptimeMillis()为基准。
- 如果在深度睡眠下,会推迟执行的时间,这个Runnable将会在和当前Hander关联的线程中被执行。
- 方法内部也是先是调用getPostMessage(Runnable)来获取一个Message,这个Message的callback字段指向了这个Runnable,然后调用sendMessageAtTime(Message,long)。
3.3 boolean postAtTime(Runnable r, Object token, long uptimeMillis)方法
代码在Handler.java 372行
/** * Causes the Runnable r to be added to the message queue, to be run * at a specific time given by uptimeMillis. * The time-base is {@link android.os.SystemClock#uptimeMillis}. * Time spent in deep sleep will add an additional delay to execution. * The runnable will be run on the thread to which this handler is attached. * * @param r The Runnable that will be executed. * @param uptimeMillis The absolute time at which the callback should run, * using the {@link android.os.SystemClock#uptimeMillis} time-base. * * @return Returns true if the Runnable was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that a * result of true does not mean the Runnable will be processed -- if * the looper is quit before the delivery time of the message * occurs then the message will be dropped. * * @see android.os.SystemClock#uptimeMillis */ public final boolean postAtTime(Runnable r, Object token, long uptimeMillis) { return sendMessageAtTime(getPostMessage(r, token), uptimeMillis); }
- 这个方法和上个方法唯一不同就是多了Object参数,而这个参数仅仅是把Message.obtain();获取的Message的obj字段的指向第二个入参token而已。最后也是调用sendMessageAtTime(Message,long)。
2.4 boolean postDelayed(Runnable r, long delayMillis)方法
代码在Handler.java 396行
/** * Causes the Runnable r to be added to the message queue, to be run * after the specified amount of time elapses. * The runnable will be run on the thread to which this handler * is attached. * The time-base is {@link android.os.SystemClock#uptimeMillis}. * Time spent in deep sleep will add an additional delay to execution. * * @param r The Runnable that will be executed. * @param delayMillis The delay (in milliseconds) until the Runnable * will be executed. * * @return Returns true if the Runnable was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that a * result of true does not mean the Runnable will be processed -- * if the looper is quit before the delivery time of the message * occurs then the message will be dropped. */ public final boolean postDelayed(Runnable r, long delayMillis) { return sendMessageDelayed(getPostMessage(r), delayMillis); }
这个方法也很简单,就是依旧是通过getPostMessage(Runnable)来获取一个Message,最后调用sendMessageDelayed(Message,long)而已。
3.5 boolean postAtFrontOfQueue(Runnable r)方法
代码在Handler.java 416行
/** * Posts a message to an object that implements Runnable. * Causes the Runnable r to executed on the next iteration through the * message queue. The runnable will be run on the thread to which this * handler is attached. * This method is only for use in very special circumstances -- it * can easily starve the message queue, cause ordering problems, or have * other unexpected side-effects. * * @param r The Runnable that will be executed. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean postAtFrontOfQueue(Runnable r) { return sendMessageAtFrontOfQueue(getPostMessage(r)); }
就是依旧是通过getPostMessage(Runnable)来获取一个Message,最后调用sendMessageAtFrontOfQueue(Message)而已。
3.6 小结
- Handler的post方案:都是通过Message getPostMessage(Runnable )中调用Message m = Message.obtain();来获取一个空的Message,然后把这个Message的callback变量指向了Runnable,最终调用相应的send方案而已。
所以我们可以这样说:
Handler的发送消息(障栅除外),无论是通过send方案还是pos方案最终都会做走到 boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) 中
参考
Android Handler机制7之消息发送
更多相关文章
- android onNewIntent
- [置顶] android 第三方jar库 反射得到自己的资源ID
- TextView设置autoLink
- Android游戏开发之旅三 View类详解
- Android初级教程_获取Android控件的宽和高 .
- 初涉android中的回调机制
- Android(安卓)如何通过menu id来得到menu item 控件
- Android(安卓)4.4以上 根据uri获取路径的方法
- Android中的Sqlite数据库操作总结