深入理解Android消息机制
Android中与消息机制相关的主要类有Looper、Handler、Message和MessageQueue。
Looper
Looper是线程消息循环处理器,正是由它不停的去从MessageQueue中获取Message,然后交给Handler处理。每个线程只能有一个Looper,在Android中只有主线程默认创建有Looper对象,其余线程需要自己创建。
下面结合源码来深入理解一下Looper,上面说了除了UI线程需要自己创建Looper对象,并且只能创建一个,看下Looper的创建方法prepare():
private static void prepare(boolean quitAllowed) {
//创建之前先判断sThreadLocal中是否有Looper对象,如果有抛异常
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//创建的Looper对象存放在sThreadLocal中,这样Looper对象就和创建它的线程关联在一起了
sThreadLocal.set(new Looper(quitAllowed));
}
前面提到UI线程不需要自己创建Looper对象,那如果创建了会是怎样呢?
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建Looper对象
Looper.prepare();
}
程序报错:
Caused by: java.lang.RuntimeException: Only one Looper may be created per thread
at android.os.Looper.prepare(Looper.java:95)
at android.os.Looper.prepare(Looper.java:90)
at com.example.wangc.myapplication.MainActivity.onCreate(MainActivity.java:20)
at android.app.Activity.performCreate(Activity.java:7117)
at android.app.Activity.performCreate(Activity.java:7108)
创建好Looper对象后,就可以调用loop()方法进入消息循环,下面看下loop()方法具体是怎么循环遍历MessageQueue中的消息并且分发。
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
//无限循环
for (;;) {
Message msg = queue.next(); // 取一条消息,没有消息会阻塞
if (msg == null) {
//消息队列中没有消息了,退出循环
return;
}
.........省略.......
try {
//分发消息,这里的msg.target其实是一个Handler
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
.........省略.......
msg.recycleUnchecked();
}
}
至此Looper在消息处理中的任务就算完成。
Message
Message是消息的载体,发送者把需要传递的消息放在Message对象中。先看一下它中的重要变量和方法。
//相当于用户定义的message识别码,用于区分不同的handler发送的消息
public int what;
//如果只需要传递整形数据的时候,不需要使用setData(Bundle)去设置数据,使用arg1,arg2开销更小。
public int arg1;
public int arg2;
//传递的对象数据
public Object obj;
//消息的状态:FLAG_IN_USE = 1 << 0 表示消息正在使用
int flags;
//消息被处理的时间
long when;
//消息携带的数据
Bundle data;
//处理该消息的handler
Handler target;
//传进来的runnable,最后也是封装成message
Runnable callback;
//对象锁,在obtain()中有使用
private static final Object sPoolSync = new Object();
//重用的message
private static Message sPool;
//可以被重用的消息数
private static int sPoolSize = 0;
//相当于最大的可重用消息数
private static final int MAX_POOL_SIZE = 50;
接下来依次分析Message对象是如何创建以及如何回收的?
Message对象的创建总的来说分为两种一是直接new一个message对象,还有一种是obtain()方法以及各种重载,但推荐使用后者。
new的方式和创建普通的Java对象一样:
Message message = new Message();
message.what = 0;
obtain()方法的重载有7种方式,这里只关注obtain()查看obtain()源码:
public static Message obtain() {
//前面提到的对象锁
synchronized (sPoolSync) {
if (sPool != null) {//有可用的message对象
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // 将message的标志设置为使用中
sPoolSize--;
return m;
}
}
//如果没有可重用的message对象还是直接new一个
return new Message();
}
到这里就可以知道为什么推荐使用obtain()来创建message对象了,因为它优先去找是否有可重用的,没有可重用的才会new message对象,这样降低了创建重复对象的开销。
Handler
到现在已经知道Looper是去循环遍历MessageQueue获取Message,那Message是如何添加到MessageQueue中去的呢?其实是通过Handler添加进去的,先看如何发送消息,
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
跟进源码发现sendMessage又是调用的sendMessageDelayed(),继续跟进,
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
可以看到这里又调用了sendMessageAtTime()方法再继续跟进,
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);
}
到这里终于看到MessageQueue了,所以最终将消息添加到MessageQueue的是enqueueMessage,
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
Handler发送消息主要分为两类方式,一类是“send”,另一类是“post”。
“send”类主要有:
这些方法只是把消息存放到MessageQueue中并指定处理时间,如果指定的时间为0表示立即处理。
“post”类的主要方法有:
其实跟进源码就可以发现,其实这些“post”类的方法也是调用的“send”类的方法发送消息,只是它们的参数要求是Runnable类对象。
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
然后在getPostMessage()方法获取到Message对象
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
对“send”类型和“post”类型做个总结的话就是:
“send”类型发送的是传统的带有id的消息;
“post”类型发送的是带有处理方法的消息。
处理Message也是由handler来完成。
public interface Callback {
public boolean handleMessage(Message msg);
}
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
在使用Handler时要注意一点,它很容易引起内存泄漏,所以在页面退出时最好调用removeCallbacksAndMessages()清空消息队列中的消息对象。
@Override
public void onDestroy() {
mHandler.removeCallbacksAndMessages(null);
}
总结
Looper
通过loop()方*询MessageQueue,并将消息分发给对应的Handler.
Handler
发送消息和处理消息,在主线程中建立Handler并利用它在子线程中向主线程发送消息,在主线程接收到消息后会对其进行处理。
MessageQueue
保存Message
下一篇: 深入理解android消息机制