安卓消息机制
安卓开发在处理不同线程通信的时候有一套消息处理机制,安卓的主线程(UI线程)是不允许处理耗时任务的。所以一般耗时任务比如常见的网络下载等任务都是子线程完成,子线程完成之后通知主线程更新UI,利用Handler类实现不同线程之间的通信:
1:实例化Message msg = mHandler.obtainMessage();
public final Message obtainMessage()
{
return Message.obtain(this);//调用的是Message类中的obtain
}
Handler类中obtainMessage方法实际调用的还是Message的static方法obtain(Handler);
public static Message obtain(Handler h) { //Message中obtain的源码
Message m = obtain();//这里是Message获取消息队列中的消息
m.target = h;//这里会传入想要获取Message的Handler,这样就会实现Message与Handler的绑定
//在Looper的循环中会调用Handler的dispatchMessage方法,而dispatchMessage
//调用的还是handleMessage(..);所以在处理异步通信的时候在主线程要重写handlerMessage
//方法来处理消息,通过what来确认消息标示
return m;
}
这里传入了Handler与消息绑定起来,这这个方法最终调用的是重载的方法obtain();
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
这里其实先在全局的消息池中,获取Message对象,其中sPool = m.next;类似于链表里的指针域(结构类似于)next其实是Message类定义的Message对象;如果消息池中有现成的对象,就只会取出,不用重新new,如果没有就返回一个
新new的消息对象。
2:获取消息对象之后用Handler(处理器)来发送消息
mHandler.sendMessage(msg);看看源码
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
这里实际调用的是sendMessageDelayed(msg,0);这里不是延时发送消息,而是延时处理消息,只不过延时时间设定的是0;
以上获取消息发送消息都是在子线程里处理的。在主线程中用Handler类处理消息
3:Handler类的构造函数需要指定回调接口,Handler类有一个接口Callback中有一个handleMessage方法,在Handler中也有一个同名方法。
public interface Callback {
public boolean handleMessage(Message msg);
}
如果不指定回调接口就要重写方法:handleMessage();
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
注释写得很清楚如果是用Handler的子类来处理消息就必须重写这个类类接受消息。
另外也可以用匿名内部类的方式来重写接口Callback里的handleMessage;
private Handler myHandler = new Handler(new Handler.Callback(){
@Override
public boolean handleMessage(Message msg) {
return true;
}
});
获得消息之后就可以做相应的处理。首先要更具Message的what属性来确定是否是自己需要的消息,这个可以在发送消息的时候指定。
这里要明确Handler是如何处理消息的实际上是调用dispatchMessage();看源码
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);//这里会有限处理Message指定的回调函数
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
这个方法首先会判断Message本身是否定义了回调,如果有,那么直接调用handlerCallback(msg);
private static void handleCallback(Message message) {
message.callback.run();
}
从代码可以看出最终调用的是Message调用的callback,而Message定义的callback字段实际上是Runnable接口,所以要调用run启动线程;
也就是说可以通过消息来启动一个子线程;
如果在实例化Message的时候没有指定回调就会判断mCallback是否实例化,mCallback是Handler定义的一个final CallBack接口字段。这个在
Handler实例化的时候调用对应的构造函数来指定
public Handler(Callback callback) {
this(callback, false);
}
如果调用的是无参构造函数的话要么用匿名内部内指定Callback,要么自己定义个Handler的子类重写handleMessage()方法。
dispatchMessage(..)也可以看出:1、如果Message实例化没有指定回调
2、如果没有重写Handler类的接口CallBack中的 boolean handleMessage()方法
3、最后才会执行Handler类中的方法void handlerMessage();