Android开发经常会用到handler,但是我们发现每次使用Handler都会出现:This Handler class should be static or leaks might occur(null)这样的提示。Android lint就是为了提示我们,这样使用Handler会容易造成内存泄漏。但是你会发现其实改成static并没有什么用。因为这并没有解决这个问题的根本。

  首先,我们得确认,为什么会有内存泄漏?因为Handler是基于消息的。每次new 出Handler,都会创建一个消息队列用于处理你使用handler发送的消息,形如:handler.send***Message。由于消息的发送总是会有先来后到的区别(如果只是这样都还好,毕竟再慢也不会太久,总归可以跑完,可能会延迟个几秒),但是如果你使用的是sendMessageDelayed(Message msg, long delayMillis)或postDelayed(Runnable r, long delayMillis)等发送延迟消息的时候,那基本内存泄漏发生的概率已经在90%以上了。

我举个通常的例子,就是我们在Activity中使用handler来更新UI控件,这是比较常见的。

 public class DemoActivity extends Activity {

     private Handler mHandler; 

     protected void onCreate(Bundle savedInstanceState) {
mHandler = new Handler();      mHandler.postDelayed(new Runnable() {
       Log.i("wytings","-----------postDelayed-------");
view.setVisibility(View.GONE);
}, 50000);
...
}
  

如果我们疯狂的对这个Activity进行横屏和竖屏切换的话,那么Activity就会不断的被销毁和重建。理论上被关闭的Activity应该会再特定时候被回收,也就是我们的内存会在一定的范围内上下起伏,但是实际上,会发现消耗的内存会随着切换横屏的次数一直慢慢增加。这其实已经说明我们的内存泄漏了,如果你会查看内存,你会发现里面有成堆的DemoActivity实例没办法回收。

  这是因为view中使用的Context就是当前的Activity,而这个runnable一旦被post,就会一直存在于队列里面,直到时间到了,被执行。意思是这个时间段内Activity即使已经被destroy了但是这个对象还是没办法回收,你会发现50秒好,会有一堆"-----------postDelayed-------"的log打印出来,虽然你已经被这个应用关闭了并且你以为即使打印也应该只打印一次……

  那怎么样才可以避免这中问题呢,如果你网上一搜你会看到很多关于弱引用的文章。这确实是一个解决的办法。其原理就是让所有在handler里面使用的对象都变成弱引用,目的就是为了可以在Android回收内存的时候,可以直接回收掉。我真觉得如果只是写这种办法的人,绝对是属于拷贝党,因为这完全是就事论事。你想想就明白,我们写这个Handler是因为我们要使用它。怎么可以通过这种弱引用的办法去处理这类问题呢?让JVM想回收就回收?!如果这样,那我们还需要在使用Bitmap的时候,recycle()干嘛,还不如直接弄成软引用得了。

这里需要再插播一下关于Java里面引用的知识:

强引用(Strong Reference) 默认引用。如果一个对象具有强引用,垃圾回收器绝不会回收它。在内存空 间不足时,Java虚拟机宁愿抛出OutOfMemory的错误,使程序异常终止,也不会强引用的对象来解决内存不足问题。
软引用(SoftReference) 如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。
弱引用(WeakReference) 在垃圾回收器一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
虚引用(PhantomReference) 如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。

如果你运气好,你会碰到一些除了写弱引用这个方法后,还有一个就是handler.removeCallbacksAndMessages(null);,就是移除所有的消息和回调,简单一句话就是清空了消息队列。注意,不要以为你post的是个Runnable或者只是sendEmptyMessage。你可以看一下源码,在handler里面都是会把这些转成正统的Message,放入消息队列里面,所以清空队列就意味着这个Handler直接被打成原型了,当然也就可以回收了。

  所以,我觉得最好的办法就是你在使用Handler的时候,在外面的Activity或者Fragment中的关闭方法中,如onDestroy中调用一下handler.removeCallbacksAndMessages(null);就可以了,不应该改成软引用。

转自:http://www.cnblogs.com/wytings/p/5225278.html

最新文章

  1. MongoDB的导入导出(7)
  2. 立体角的单位——立体弧度(sr)
  3. 查看oracle死锁进程并结束死锁
  4. 变量声明提升 Vs. 函数声明提升
  5. Bootstrap2和3的区别
  6. JS中的this好神奇,都把我弄晕了
  7. Android 源码VecotorDrawable
  8. CSS- 控制图片显示指定大小 并超过大小自动缩小
  9. 极简主义,对逻辑操作符||和&&深度运用的理解
  10. 几句话实现导航栏透明渐变 – iOS
  11. Oracle优化技术
  12. 揭秘传智播客毕业班的超级薪水7k内幕系列II----Offer工资表5.7k,为什么不能让老师就业就业
  13. 10分钟精通SharePoint - SharePoint发展历程
  14. React Native 系列(七) -- ListView
  15. 读书笔记---HTML5实战 MARCO CASARIO(前六章)
  16. Java队列学习
  17. Asp.Net SignalR 多平台的Client与Server
  18. How to Disable/Enable IP forwarding in Linux
  19. Oracle中分页查询和联表查询
  20. LCTF wp简单复现

热门文章

  1. C预处理,条件编译
  2. windows下SSH客户端远程访问Linux出现错误
  3. 分布式文件系统 - FastDFS
  4. cocos2dx中的菜单项CCMenuItem及其五个子类的使用
  5. C#基础原理拾遗——面试都爱问的委托和事件(纠正)
  6. MVC与WebForm的一些区别
  7. 【转】如何设置Android软键盘的默认不弹出?
  8. windows 2012 服务器打开ping端口,开通远程连接
  9. 关于json的知识整理
  10. BZOJ 1051: [HAOI2006]受欢迎的牛 强连通缩点