Android消息机制主要指的是Handler的运行机制。
(注意,消息机制中的Handler是android.os包下的Handler,不是java.util.logging包中的Handler,开发中注意不要到错包。)
Handler是消息机制的上层接口。Handler将任务切换到handler所在的线程执行。
与handler相关的有MessageQueue、Looper。其中,
MessageQueue中文名称是消息队列,内部存储了一组消息,并以队列的形式向外提供插入删除操作。MessageQueue以队列的形式命名,而内部实现是单链表。内部提供了next方法读取一条消息,并从消息队列中删除。
Looper是个无限循环,当调用Looper.prepare和Looper.loop方法后Looer就开始工作了。Looper以无限循环方式检查是否有消息,有就处理,无就等待。Looer中有个ThreadLocal对象,用来存储每个线程的数据,通过ThreadLocal可以获取每个线程的Looper,ThreadLocal保证每个线程的数据互不干扰。
流程
Handler创建时,会使用当前线程的Looper来构造内部的消息循环系统。每个Handler对应一个Looper。如果Handler所在的线程没有对应的Looer,则会抛出一个这样的异常信息:
Can't create handler inside thread that has not called Looper.prepare()。
解决办法就是,在Handler创建之前,调用Looper.Prepare初始化looper,并在handler创建后调用Looper.loop开启循环,若不调用Looper.loop则Looper是无法工作的。
这样的情况一般出现在子线程创建handler对象的时候。为什么主线程我们没有创建Looper对象,却没有抛出这样的异常呢?
原因就是在MainThread中,系统给我们初始化了Looper对象。查看源码可发现这句:
Looper.prepareMainLooper();//创建主线程Looper和MessageQueue
Looper.Loop();//开启主线程Looper
当调用handler.post(Runnable runnable)方法后,会将Runnable对象投递到handler内部的Looer中处理。也可以通过Handler.sendMessage(Message msg)方法来发送一个消息,也是会在Looer中处理。查看源码得知,handler.post方法最终调用的也是handler.send方法来实现的。
当handler.send方法被调用时,它会调用MessageQueue的enqueueMessage将消息存放到MessageQueue中。当Looper检测到时,会调用next方法读取此消息,并从MessageQueue中删除。
相关代码如下:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
看一下DispatchMessage方法执行流程:
在dispatchMessage方法中有以下几个分支:
先检查Message的callback(是一个Runnable类型的对象)是否为null,如果不为null就执行HandlerCallBack来处理消息;
检查mCallback(是一个CallBack接口类型对象)是否为null,如果不为null,就执行mCallback接口对象的handlerMessage方法来处理消息;
最后则是调用handler的handlerMessage方法来处理消息。
题外话,子线程为什么不能直接访问UI?
android的控件不是线程安全的。在线程中访问ui,可能导致ui不可控。考虑到ui访问效率又不能是主线程阻塞,故不能采用加锁机制。所以在
Android 4.0以后做出了这样的规定,要求子线程不能访问ui,否则会直接抛出异常。异常信息是这样的:
Only the original thread that created a view hierarchy can touch its views.
Handler的应用场景
通常在子线程中将结果发送给主线程,通知主线程更新ui。
也可以在主线程中将任务加入到消息队列顺序执行。
源码分析
//可以直接实现此接口来初始化handler,而不必去实现创建Handler的子类
public interface Callback {
public boolean handleMessage(Message msg);
}
//handlerMessage是一个空方法,子类若要通过这种方式处理消息,子类必须自己实现
public void handleMessage(Message msg) {
}
//消息处理,分析见上述
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
下面是handler的几个构造方法:
public Handler() {
this(null, false);
}
public Handler(Callback callback) {
this(callback, false);
}
//使用指定的Looper对象构造handler
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
public Handler(boolean async) {
this(null, async);
}
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
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;
}
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
handler的几个构造,由于代码不复杂,这里不再说明。
接下来看一系列的obtainMessage方法,及它们的重载:
//Message.obtainMessage获取的结果是通过Message.Target设置的值
public final Message obtainMessage()
{
return Message.obtain(this);
}
public final Message obtainMessage(int what)
{
return Message.obtain(this, what);
}
public final Message obtainMessage(int what, Object obj)
{
return Message.obtain(this, what, obj);
}
public final Message obtainMessage(int what, int arg1, int arg2)
{
return Message.obtain(this, what, arg1, arg2);
}
public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
{
return Message.obtain(this, what, arg1, arg2, obj);
}
接着看几个比较重要的方法:
//post方法与postDelayed方法一样,最终调用的是sendMessageDelayed方法
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean postAtTime(Runnable r, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
//从消息队列中移除指定的Runnable对象
public final void removeCallbacks(Runnable r)
{
mQueue.removeMessages(this, r, null);
}
//移除消息队列中的Runnable对象,如果object参数不为null 则会移除所有的
public final void removeCallbacks(Runnable r, Object token)
{
mQueue.removeMessages(this, r, token);
}
下面是sendmessage的一系列方法,
//将消息添加到消息队列,如果添加成功会返回true,否则返回false
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
//将一个仅有what值的message添加到消息队列,添加成功返回true,否则返回false
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
//在指定的时间后发送一个仅有what值的message,添加到消息队列
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
//在指定的时间将仅有what值的message添加到消息队列
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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);
}
//从消息队列中移除指定what值的message
public final void removeMessages(int what) {
mQueue.removeMessages(this, what, null);
}
public final void removeMessages(int what, Object object) {
mQueue.removeMessages(this, what, object);
}
public final void removeCallbacksAndMessages(Object token) {
mQueue.removeCallbacksAndMessages(this, token);
}
接下来的代码,是创建了一个IMessager的实现类。可以看出使用了Binder机制。为了实现对使用Messenger跨进程发送消息的处理。涉及到进程通信,这里先不多讲。
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
private static Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain();
m.obj = token;
m.callback = r;
return m;
}
private static void handleCallback(Message message) {
message.callback.run();
}
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
final boolean mAsynchronous;
IMessenger mMessenger;