Android Handler 避免内存泄漏的用法总结

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

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

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

 1 public class DemoActivity extends Activity {
 2 
 3     private Handler mHandler; 
 4 
 5     protected void onCreate(Bundle savedInstanceState) {
 6         mHandler = new Handler();
 7 
 8      mHandler.postDelayed(new Runnable() {
 9        Log.i("wytings","-----------postDelayed-------");
10             view.setVisibility(View.GONE);
11         }, 50000);
12         ...
13     }
14   

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

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

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

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

强引用(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开发

相关文章
相关标签/搜索