Android消息机制使用注意事项,防止泄漏
在Android的线程通信当中,使用频率最多的就是Android的消息处理机制(Handler.send()、View.post()、Asynctask.excute()等等都使用到了消息处理机制)。Android中UI线程默认实现了该机制,其它工作线程要想跟UI线程一样拥有该机制,就必须人为去实现该机制,该机制的实现也相当简单暂且忽略。对于Android里的消息处理,涉及到Handler,Looper,Message,Message Queue等概念。
- Message:消息,其中包含了what(消息ID),obj(消息处理对象,这是引起泄漏的主要原因,下面会谈到)以及其它处理的数据(arg1,arg2,messenger),由MessageQueue统一列队,终由Handler处理。
- Handler:线程消息管理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。
- MessageQueue:线程的消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。
- Looper:一个线程只可以产生一个Looper对象,用来管理MessageQueue,它就像一个消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。
为了便于理解Message泄漏,首先看一段Message的源代码:
// sometimes we store linked lists of these things
/*package*/ Message next; private static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0; private static final int MAX_POOL_SIZE = 50; /**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
sPoolSize--;
return m;
}
}
return new Message();
}
从以上代码可以看到Message类有一个全局的消息池,池的大小为50,用于存放Message对象。Message引起泄漏的问题就出在这个全局的消息池。我们知道Java的回收是由GC来进行的,而当我们强引用着一个对象时,GC是不会将这个对象回收的。正好这个全局的消息池,里面存储的Message必然是一个强引用。造成Message泄漏的一个最大的根源是Message的obj字段,这个字段是Object类型的,因此obj的byte数是可以很大的。
有些人可能会说,那我对obj这个参数做弱引用让GC能够回收好不就得了。这个方法虽然能解决GC的回收,但是有一个致命的问题,就是弱应用是极不安全的,GC想要什么时候回收弱应用对象就什么时候回收。所以我们应该换一个解决方方法,处理完一个Message就从全局当中移除一个。对于这个实现,Android的Handler有三个暴露的方法可供使用,removeMessages(int what)、removeMessages(int what, Object object)和removeCallbacksAndMessages(Object token)。具体使用可见如下代码:
@Override
public void handleMessage(android.os.Message msg) {
if (msg == null) {
return;
}
removeXXXXX(); }
}
removeMessages(int what)和removeMessages(int what, Object object)会调用MessageQueue的removeMessages(Handler h, int what, Object object),该方法源码如下:
void removeMessages(Handler h, int what, Object object) {
if (h == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
while (p != null && p.target == h && p.what == what
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycle();
p = n;
}
// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.what == what
&& (object == null || n.obj == object)) {
Message nn = n.next;
n.recycle();
p.next = nn;
continue;
}
}
p = n;
}
}
}
removeCallbacksAndMessages(Object token)会调用MessageQueue的removeCallbacksAndMessages(Handler h, Object object)方法,该方法源码如下:
void removeCallbacksAndMessages(Handler h, Object object) {
if (h == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
while (p != null && p.target == h
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycle();
p = n;
}
// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && (object == null || n.obj == object)) {
Message nn = n.next;
n.recycle();
p.next = nn;
continue;
}
}
p = n;
}
}
}
Android消息机制使用注意事项,防止泄漏的更多相关文章
- Android消息机制
每一个Android应用在启动的时候都会创建一个线程,这个线程被称为主线程或者UI线程,Android应用的所有操作默认都会运行在这个线程中. 但是当我们想要进行数据请求,图片下载,或者其他耗时操作时 ...
- Android开发之漫漫长途 ⅥI——Android消息机制(Looper Handler MessageQueue Message)
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...
- Android开发之漫漫长途 Ⅶ——Android消息机制(Looper Handler MessageQueue Message)
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...
- Android 进阶14:源码解读 Android 消息机制( Message MessageQueue Handler Looper)
不要心急,一点一点的进步才是最靠谱的. 读完本文你将了解: 前言 Message 如何获取一个消息 Messageobtain 消息的回收利用 MessageQueue MessageQueue 的属 ...
- 每日一问:Android 消息机制,我有必要再讲一次!
坚持原创日更,短平快的 Android 进阶系列,敬请直接在微信公众号搜索:nanchen,直接关注并设为星标,精彩不容错过. 我 17 年的 面试系列,曾写过一篇名为:Android 面试(五):探 ...
- 史上最详细的Android消息机制源码解析
本人只是Android菜鸡一个,写技术文章只是为了总结自己最近学习到的知识,从来不敢为人师,如果里面有不正确的地方请大家尽情指出,谢谢! 606页Android最新面试题含答案,有兴趣可以点击获取. ...
- Android消息机制:Looper,MessageQueue,Message与handler
Android消息机制好多人都讲过,但是自己去翻源码的时候才能明白. 今天试着讲一下,因为目标是讲清楚整体逻辑,所以不追究细节. Message是消息机制的核心,所以从Message讲起. 1.Mes ...
- Android消息机制不完全解析(上)
Handler和Message是Android开发者常用的两个API,我一直对于它的内部实现比较好奇,所以用空闲的时间,阅读了一下他们的源码. 相关的Java Class: androi ...
- Android消息机制不完全解析(下)
接着上一篇文章Android消息机制不完全解析(上),接着看C++部分的实现. 首先,看看在/frameworks/base/core/jni/android_os_MessageQueue.cpp文 ...
随机推荐
- 02_jQuery对象初识(二)筛选器1
0. HTML对象和jQuery对象的区别: 1.jQuery对象转换成DOM对象,用索引取出具体的标签 2.DOM对象转换成jQuery对象,$(DOM对象) 注意:jQuery对象保存到变量的时候 ...
- hadoop2.x 完全分布式详细集群搭建(图文:4台机器)
在准备之前说一下本次搭建的各节点角色,进程. nameNode 进程:NameNode dataNode 进程:DataNode resourceManager :ResourceManager n ...
- quartz 定时任务配置文件信息
quartz 定时任务配置文件有五大要素,配置好这五大要素,quartz 就能够正常的工作. 五大要素分别是: 1.工作的 bean:具体是哪个 Java 类来作为定时任务的文件入口,并配置该 bea ...
- Useradd- Linux必学的60个命令
1.作用 useradd命令用来建立用户帐号和创建用户的起始目录,使用权限是超级用户. 2.格式 useradd [-d home] [-s shell] [-c comment] [-m [-k t ...
- [JLOI2015]战争调度【暴力+树形Dp】
Online Judge:Bzoj4007,Luogu P3262 Label:暴力,树形Dp 题解 参考了这篇blog https://www.cnblogs.com/GXZlegend/p/830 ...
- watch、tail联合使用
因为用了tmux,不想调整窗格大小,只想输出命令结果的最后几行,所以就想出了这个方法. watch.tail联合用法 watch 'echo "`nvidia-smi`" | ta ...
- 让pandoc输出pdf时支持中文
主机环境为:Ubuntu 12.04 LTS.对于RH系列,yum安装包的名称可能会有不同,不过yum联想能力比较强,应该不是问题. 安装pandoc,安装tex-live sudo apt-get ...
- oauth2使用心得-----基本概念以及认证服务器搭建
应用场景 我们假设你有一个“云笔记”产品,并提供了“云笔记服务”和“云相册服务”,此时用户需要在不同的设备(PC.Android.iPhone.TV.Watch)上去访问这些“资源”(笔记,图片) 那 ...
- 注册.NET Framework
C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe /i
- pixhawk 常见问题 持续更新
红灯蓝灯闪,初始化中,请稍等 黄灯双闪,错误,系统拒绝解锁 黄灯闪,遥控器关闭 黄灯快速闪且滴滴响,电池保护激活 蓝灯... 未见过.... 绿灯闪: 已加锁,GPS锁定已获得. 准备解锁. 从加锁状 ...