(点击上方公众号,可快速关注)
来源:伯乐在线专栏作者 - PleaseCallMeCoder
链接:http://android.jobbole.com/84957/
点击 → 了解如何加入专栏作者
接上文
接下来我们看一下handler是如何发送消息的
/**
* 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);
}
/**
* 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);
}
/**
* 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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
这里我们只列出了一种调用关系,其他调用关系大同小异,我们来分析一下
调用getPostMessage(r),把runnable对象添加到一个Message对象中。
sendMessageDelayed(getPostMessage(r), 0),基本没做什么操作,又继续调用sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)方法,在这个方法里拿到创建这个Handler对象的线程持有的MessageQueue。
调用enqueueMessage(queue, msg, uptimeMillis)方法,给msg对象的target变量赋值为当前的Handler对象,然后放入到MessageQueue。
那发送消息说完了,那我们的消息是怎样被处理的呢?
我们看到message.target为该handler对象,这确保了looper执行到该message时能找到处理它的handler,即loop()方法中的关键代码。
/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
*
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
public interface Callback {
public boolean handleMessage(Message msg);
}
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
我们看到这里最终又调用到了我们重写的handleMessage(Message msg)方法来做处理子线程发来的消息或者调用handleCallback(Message message)去执行我们子线程中定义并传过来的操作。
思考
为什么要有Handler机制
这个问题可以这么考虑
我们如何在子线程更新UI?——使用Handler机制传递消息到主线程(UI线程)
为什么我们不在子线程更新UI呢?——因为Android是单线程模型
为什么要做成单线程模型呢?——多线程并发访问UI可能会导致UI控件处于不可预期的状态。如果加锁,虽然能解决,但是缺点也很明显:1.锁机制让UI访问逻辑变得复杂;2.加锁导致效率低下。
Handler机制与命令模式
我在之前分享过Android源码中的命令模式,我们仔细分下一下不难看出Handler机制其实是一个非典型的命令模式。
Android主线程是如何管理子线程消息的
我们知道Android上一个应用的入口,应该是ActivityThread。和普通的Java类一样,入口是一个main方法。
public static void main(String[] args) {
//~省略部分无关代码~
//创建Looper和MessageQueue对象,用于处理主线程的消息
Looper.prepareMainLooper();
//创建ActivityThread对象
ActivityThread thread = new ActivityThread();
//建立Binder通道 (创建新线程)
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
//消息循环运行
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
我们可以看到其实我们在这里初始化了我们主线程(UI)的Looper并且启动它。然后就可以处理子线程和其他组件发来的消息了。
为什么主线程不会因为Looper.loop()里的死循环卡死或者不能处理其他事务
这里涉及到的东西比较多,概括的理解是这样的
主线程大多数时候都是处于休眠状态,并不会消耗大量CPU资源。
既然是死循环又如何去处理其他事务呢?答案是通过创建新线程的方式。
我们看到main方法里调用了thread.attach(false),这里便会创建一个Binder线程(具体是指ApplicationThread,Binder的服务端,用于接收系统服务AMS发送来的事件),该Binder线程通过Handler将Message发送给主线程。
ActivityThread对应的Handler是一个内部类H,里边包含了启动Activity、处理Activity生命周期等方法。
参考资料
http://www.cnblogs.com/codingmyworld/archive/2011/09/12/2174255.html
http://czpsailer.iteye.com/blog/655942
https://www.zhihu.com/question/34652589
专栏作者简介( 点击 → 加入专栏作者 )
PleaseCallMeCoder:我是 PleaseCallMeCoder,一个小小的90后程序员。热衷于移动开发,喜欢研究新技术,奔跑在成为大神的路上。
打赏支持作者写出更多好文章,谢谢!
关注「安卓开发精选」
看更多精选安卓技术文章
↓↓↓