大家都知道Android应用程序是通过消息来驱动的。每开启一个应用进程,我们都会在当前应用进程的主线程成创建一个消息队列,和Handler来处理应用程序中的消息。不管是刷新界面,或者是启动组件等等,都和消息相关。所以Message对象在我们的应用程序中使用时很频繁的。
一般情况下,我们会通过Handler去发送一个消息,而这个消息(即Message对象)我们可以通过关键字new进行创建,也可以通过Message.obtain()方法进行创建。在Android源码中,我们在Message的构造方法上方可以看到如下一段注释:

    /** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).    */    public Message() {    }

这段注释的意思是:更加建议我们使用Message.obtain()方法来获取一个Message对象。

为什么Android官方更加建议我们使用Message.obtain()方法呢?下面我将从源码角度,带大家了解一下其中的奥妙。

既然它建议我们使用obtain()方法,那我们就来看看它为我们做了些什么事。
以下源码都源码基于Android8.0。

1.解析Message.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();    }

可以看到在obtain方法中,如果sPool不为null的时候,还是会调用new Message()来创建一个Message对象。那么这个sPool又是个什么东西呢?其实呢从上面代码我们就可以看出来,它其实是一个链表。每个Message对象都有next字段,它的类型也是Message。上面的代码其实就是把链表中的第一个节点返回,然后把sPool置为第一个Messgae的next对象,即下一个节点。那我们这个sPool对象是怎么生成的呢?我们在来找一找答案。我们在Message类中搜索一下sPool这个对象,看看什么时候会往它里面添加Message对象。我们可以找到recycleUnchecked()方法,recycleUnchecked()是在recycle()方法中被调用的。

2.解析recycle()方法和recycleUnchecked()方法

    public void recycle() {        //判断当前Message对象是否能被回收        if (isInUse()) {            if (gCheckRecycle) {                throw new IllegalStateException("This message cannot be recycled because it "                        + "is still in use.");            }            return;        }        //可以回收调用recycleUnchecked()方法        recycleUnchecked();    }  void recycleUnchecked() {        // Mark the message as in use while it remains in the recycled object pool.        // Clear out all other details.        //清除Message对象里面成员变量的信息        flags = FLAG_IN_USE;        what = 0;        arg1 = 0;        arg2 = 0;        obj = null;        replyTo = null;        sendingUid = -1;        when = 0;        target = null;        callback = null;        data = null;        synchronized (sPoolSync) {           //当sPoolSize大小小于MAX_POOL_SIZE即50时,继续往池中添加。           //sPoolSize可以理解为Message池内Messgae对象的数量。            if (sPoolSize < MAX_POOL_SIZE) {                //当前Message对象当作第一个链表的第一个节点                next = sPool;                sPool = this;                sPoolSize++;            }        }    }

好了现在我们知道了当Message对象被回收的时候,会像池中添加一个Messgae对象。那么什么时候会回收一个Messsge对象呢。可以猜想以下,一个对象不用了之后才会被回收,在Android消息机制中,Looper会通过loop()方法想消息队列中去消息,我们去loop()方法中找找,看看是否会调用我们Message的回收方法。

3.解析Looper.loop()方法

源码如下:

 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;        // Make sure the identity of this thread is that of the local process,        // and keep track of what that identity token actually is.        Binder.clearCallingIdentity();        final long ident = Binder.clearCallingIdentity();        // Allow overriding a threshold with a system prop. e.g.        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'        final int thresholdOverride =                SystemProperties.getInt("log.looper."                        + Process.myUid() + "."                        + Thread.currentThread().getName()                        + ".slow", 0);        boolean slowDeliveryDetected = false;       //无限循环        for (;;) {            Message msg = queue.next(); // might block            if (msg == null) {                // No message indicates that the message queue is quitting.                return;            }          //省略部分代码          .....          .....             try {               //调用Handler的dispatchMessage来处理消息                msg.target.dispatchMessage(msg);                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;            } finally {                if (traceTag != 0) {                    Trace.traceEnd(traceTag);                }            }                 //此处省略部分代码     .....     .....            //调用回收处理完成的Message的方法            msg.recycleUnchecked();        }    }

可以清楚的看到当我们的Looper对象处理完我们的Message时,会去调用回收Message的方法,向我们的Message对象中的复用池中添加一个Message对象。

4.总结

分析到这里,我相信所有朋友都明白了。Message类里维护了一个sPool对象。可以理解成一个Message链表,这个链表默认的最大长度是50。在Android消息机制中,每当一个Message对象被处理完成之后,都会被放入这个池中,为我们提供了复用。当我们调用Message.obtain()方法时,如果复用池中存在Message对象,我们就不会去创建一个新的Message对象。这样就避免了频繁创建和销毁Messgae对象的带来的性能开销。

更多相关文章

  1. Android(安卓)用户界面---操作栏(Action Bar 三)
  2. Android(安卓)UI设计小知识——富文本
  3. Android(安卓)TextView中标点符号或英文导致自动换行问题
  4. Android序列化详解及最佳实践(Serialize&Parcel)
  5. Launcher功能的修改及添加,本篇是一些小功能的展示,通知栏显隐,dock
  6. 《Android开发艺术探索》之学习笔记(三)View的基础知识
  7. 三种方法,刷新 Android(安卓)的 MediaStore!让你保存的图片立即出
  8. Android(安卓)launcher动态Icon的实现方法
  9. 防止Android过快点击造成多次事件的三种方法

随机推荐

  1. android apilevel和android系统版本对应
  2. Android开发技术文章整理
  3. android studio多渠道号,多包名打包
  4. android中GPS信息的获取
  5. Android(安卓)WIFI热点默认安全性的修改
  6. [51CTO]Android消息机制
  7. android获取电话号码实例
  8. Android:创建快捷方式
  9. Android(安卓)framwork 锁屏界面开发 笔
  10. Android官方入门文档[11]支持不同平台版