欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

深入理解Android消息机制

程序员文章站 2022-07-14 18:25:24
...

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”类主要有:

深入理解Android消息机制

这些方法只是把消息存放到MessageQueue中并指定处理时间,如果指定的时间为0表示立即处理。

“post”类的主要方法有:

深入理解Android消息机制

其实跟进源码就可以发现,其实这些“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