Android中与消息机制相关的主要类有Looper、Handler、Message和MessageQueue。
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识别码,用于区分不同的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对象,这样降低了创建重复对象的开销。
到现在已经知道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); }
处理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); }
通过loop()方法轮询MessageQueue,并将消息分发给对应的Handler.
发送消息和处理消息,在主线程中建立Handler并利用它在子线程中向主线程发送消息,在主线程接收到消息后会对其进行处理。
保存Message