Android 异步消息处理机制前篇(二):深入理解Message消息池

上一篇中共同探讨了ThreadLocal,这篇我们一起看下常提到的Message消息池到底是怎么回事,废话少说吧,进入正题。

对于稍有经验的开发人员来说我们在使用Handler发送异步消息获取Message的时候都会使用如下代码获取一个Message对象:

1 Message msg = mHandler.obtainMessage();

而不是直接new一个:

1 Message msg = new Message();

二者的主要区别就是上面的用到缓存池概念,如果池中有闲着的则拿来用,没有则new一个Message。后者则没有这个机制,直接new一个拿来用。

接下来我们分析一下这个缓存池是怎么实现的。

Message缓存池源码分析

Handler中obtainMessage()方法实质还是调用的Message中obtain()方法,这里就直接看Message中obtain()方法源码了:

 1 public static Message obtain() {
 2         synchronized (sPoolSync) {
 3             if (sPool != null) {
 4                 Message m = sPool;
 5                 sPool = m.next;
 6                 m.next = null;
 7                 m.flags = 0; // clear in-use flag
 8                 sPoolSize--;
 9                 return m;
10             }
11         }
12         return new Message();
13  }

第3行首先判断sPool是否为null,如果为null则直接执行12行直接new一个Message返回,整个方法结束,sPool是什么鬼?定义如下:

1 private static Message sPool;

看到了吧,就是一个Message对象,sPool其实就相当于一个头指针,指向缓存池中第一个缓存的Message,分析完所有就会自然明白了其作用。

继续向下分析。

sPool不为null则进入4-9行代码逻辑,sPool不为null说明缓存池中存在空闲的Message.

第4行记录sPool,并且第9行返回m作为整个方法的返回值,也就是返回缓存池中的空闲Message供外部使用,不需要额外内存开销。

第5行sPool指向下一个缓存对象。

第6行m.next置为null,到这里最重要的逻辑就完了,也许你还蒙蔽呢,这是什么啊,其实很简单Message的缓存池其实就是用了一个数据结构-单向链表。

接下来又要展示我强大的画图能力了,没有什么是一个图示不能解决的:

假设此时缓存池中有三个空闲message:message1,message2,message3。sPool一开始指向头部message1。

执行第4行代码相当于图中步骤①,没什么好解释的。

执行第5行代码相当于图中步骤②,sPool指向下一个缓存message,此处为message2.

执行第6行代码相当于图中步骤③,message1与message2断开连接。

怎么样这样解释该明白了,其实本身就很简单。

7,8行就是清除标记以及改变sPoolSize大小,sPoolSize用来记录缓存池中存在的元素个数,缓存池大小是有限制的,超过规定大小则不能再往里面添加。

obtain()总结

好了,到此主要逻辑就分析完了,obtain()主要逻辑就是先判断缓存池中是否存在空闲message,如果存在则返回头部message,并且指针指向下一个空闲message,然后头部的message与之后链表  断开连接。如果不存在空闲message则直接new一个直接返回。

上面的逻辑都是从缓存池中获取的操作,那什么时候向缓存池中存放呢?我们继续向下分析。

Message类中recycle()方法是用于回收用完的mesage,将此message会收到缓存池中,是这样的吗?我们看下源码就知道了:

 1 public void recycle() {
 2         if (isInUse()) {
 3             if (gCheckRecycle) {
 4                 throw new IllegalStateException("This message cannot be recycled because it "
 5                         + "is still in use.");
 6             }
 7             return;
 8         }
 9         recycleUnchecked();
10 }

recycle方法中主要判断当前message是否正在使用中,如果正在使用则抛出异常,没被使用则调用recycleUnchecked()方法,接下来看下recycleUnchecked():

 1 void recycleUnchecked() {
 2         // Mark the message as in use while it remains in the recycled object pool.
 3         // Clear out all other details.
 4         flags = FLAG_IN_USE;
 5         what = 0;
 6         arg1 = 0;
 7         arg2 = 0;
 8         obj = null;
 9         replyTo = null;
10         sendingUid = -1;
11         when = 0;
12         target = null;
13         callback = null;
14         data = null;
15
16         synchronized (sPoolSync) {
17             if (sPoolSize < MAX_POOL_SIZE) {
18                 next = sPool;
19                 sPool = this;
20                 sPoolSize++;
21             }
22         }
23 }

4-14主要就是清除一些当前标记。

17行,MAX_POOL_SIZE就是规定的缓存池中最多缓存message的个数,如果当前已经存储的数量小于规定的最大缓存个数则继续向下执行。

18,19行就是重点了,又到展示我强大画图能力的时候了,一张图解决:

比如缓存池中链表中为message2,message3,sPool指向头部message2。

此时,message1被回收执行recycle()操作。最终执行到recycleUnchecked()的18,19行逻辑。

18行:相当于将图中message1的next指针指向sPool,此时sPool指向message2,也就是将message1与message2链接,也就是图中①操作。

19行:sPool重新定位到当前被回收的message,这里也就是message1。相当于图中②操作

recycle()总结

好了,到这里回收就讲完了,最主要就是18,19行逻辑,recycle()最主要就是将当前message放入缓存池链表头部。

到此,我想讲解的就完了,本篇核心就是数据结构中单项链表的实际应用,如果单向链表你很熟悉,我觉得这里应该很轻松的就理解了,即使不是很熟悉,用心思考一下也应该能理解,这里不难理解。

本篇就到此为止了,下一篇Android异步消息处理机制完全解析。

时间: 2024-08-26 12:41:32

Android 异步消息处理机制前篇(二):深入理解Message消息池的相关文章

篇二、理解Android Studio的视图和目录分析,这个是转载

原文链接:http://blog.csdn.net/siyehuazhilian/article/details/42123563 AS一共有三种视图.我们来分别分析每一种视图的作用. 一.Project视图.(白色字体的目录/文件可不关注) 图片中的链接 Gralde介绍:http://stormzhang.com/devtools/2014/12/18/android-studio-tutorial4/ GIT/github使用:http://www.worldhello.net/gotgi

Android 异步加载图像优化,如:引入线程池、引入缓存

关于Android 从网络上异步加载图像: 个人总结,重在分享! 异步加载图像,由于Adnroid Ui 更新支持单一线程原则,所以从网络上取数据并更新到界面上,为了不阻塞主线程 首先要想到以下方法. 1.在主线程中 new 一个Handler对象,加载图像(优化) 示1:private void  loadImage(final String url, final int id){ handler.post(new Runnable(){ public void run(){ Drawable

系统学习消息队列分享(二) 为什么需要消息队列?

消息队列是最古老的中间件之一,从系统之间有通信需求开始,就自然产生了消息队列.但是给消息队列下一个准确的定义却不太容易.我们知道,消息队列的主要功能就是收发消息,但是它的作用不仅仅只是解决应用之间的通信问题这么简单. 我们举个例子说明一下消息队列的作用.话说小袁是一家巧克力作坊的老板,生产出美味的巧克力需要三道工序:首先将可可豆磨成可可粉,然后将可可粉加热并加入糖变成巧克力浆,最后将巧克力浆灌入模具,撒上坚果碎,冷却后就是成品巧克力了. 最开始的时候,每次研磨出一桶可可粉后,工人就会把这桶可可粉

如何在App中实现IM功能之二快速实现离线消息模块——箭扣科技Arrownock

如何在App中实现IM功能 之二 快速实现离线消息模块 一个App在实际使用聊天功能的时候,并非是一直呆在一个界面的,在等待好友发消息来的同时,有可能已经跳转到其他界面,也有可能切换到其他App. 在当前的App进入后台.好友发来消息时,需要给设备推送一条消息.以安卓为例,收取离线消息通知需要绑定anPush,具体做法是调用anIM.bindAnPushService(anID, AppKey, anPushType). 在App进入后台时,调用anIM.disconnect():在App回到前

Android异步处理系列文章四篇之二 使用AsyncTask异步更新UI界面

Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面Android异步处理二:使用AsyncTask异步更新UI界面Android异步处理三:Handler+Looper+MessageQueue深入详解Android异步处理四:AsyncTask的实现原理 Android异步处理二:使用AsyncTask异步更新UI界面 概述: AsyncTask是在Android SDK 1.5之后推出的一个方便编写后台线程与UI线程交互的辅助类.AsyncTask的内部实现

Android多线程编程之Handler篇(消息机制)

Android多线程编程之Handler篇(消息机制) Android的消息机制主要是指Handler的运行机制,Handler的运行需要底层的MessageQueue和Looper的支撑. MessageQueue 消息队列,以队列的形式(实为单链表结构)对外提供插入和删除的工作, Looper 以无限循环的形式不断获取MessageQueue中的消息,有则处理,无则等待. ThreadLocal ThreadLocal可以在不同的线程互不干扰的存储并提供数据,通过ThreadLocal可以很

Android异步处理系列文章四篇之三

Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面Android异步处理二:使用AsyncTask异步更新UI界面Android异步处理三:Handler+Looper+MessageQueue深入详解Android异步处理四:AsyncTask的实现原理 Android异步处理三:Handler+Looper+MessageQueue深入详解 概述:Android使用消息机制实现线程间的通信,线程通过Looper建立自己的消息循环,MessageQueue是F

Android异步处理系列文章四篇之一使用Thread+Handler实现非UI线程更新UI界面

目录: Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面Android异步处理二:使用AsyncTask异步更新UI界面Android异步处理三:Handler+Looper+MessageQueue深入详解Android异步处理四:AsyncTask的实现原理 Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面 概述:每个Android应用程序都运行在一个dalvik虚拟机进程中,进程开始的时候会启动一个主线程(MainTh

Android异步处理二:使用AsyncTask异步更新UI界面

Android异步处理二:使用AsyncTask异步更新UI界面 - lzc的专栏 - 博客频道 - CSDN.NET 在<Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面>中,我们使用Thread+Handler的方式实现了异步更新UI界面,这一篇中,我们介绍一种更为简洁的实现方式:使用AsyncTask异步更新UI界面. 概述: AsyncTask是在Android SDK 1.5之后推出的一个方便编写后台线程与UI线程交互的辅助类.AsyncTask的