在Android异步消息处理中,
Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { // } };
但当我们这么写时,编译器会给出警告提示:Handler类应该是静态的,可能发生内存泄漏。
原因:
在Java中,非静态的内部类和匿名内部类都会隐式地持有其外部类的引用。静态的内部类不会持有外部类的引用。
这里Handler是一个匿名内部类的实例,其持有外面的Activity的引用,所以当Handler伴随一个耗时后台线程时就会出现Activity无法回收,进而内存泄露。
解决方法:
一:将Handler声明为静态内部类。
因为静态的内部类不会持有外部类的引用,所以不会导致外部类实例的内存泄露。由于Handler不再持有外部类对象的引用了,导致程序不允许你在Handler中操作Activity中的对象。所以如果要在静态内部类中调用外部的Activity时,我们使用弱引用来处理(WeakReference)。
private static class MyHandler extends Handler { private final WeakReference<SampleActivity> mActivity; public MyHandler(SampleActivity activity) { mActivity = new WeakReference<SampleActivity>(activity); } @Override public void handleMessage(Message msg) { SampleActivity activity = mActivity.get(); if (activity != null) { // ... } } }
二:postDelayed(new Runnable(),10000)情况
mHandler.postDelayed(new Runnable() { @Override public void run() { // } }, 10000);
在handler的post方法中我们加入了一个匿名的runnable,同时我将其执行延迟了10秒。
被延迟的消息会在被处理之前一直存在于主线程消息队列中。同时new Runnable也是匿名内部类实现的,同样也会持有Activity的引用。
这时候我们还需要将Runnable设置为静态的成员属性。
private static final Runnable sRunnable = new Runnable() { @Override public void run() { /* ... */ } };
同时onCreate()中mHandler.postDelayed(sRunnable, 10000);
另一个方法是使用Handler的removeCallbacksAndMessages ()方法,把消息对象从消息队列移除。
当参数为null的时候,可以清除掉所有跟次handler相关的Runnable和Message,我们在onDestroy中调用次方法清理掉所有Messages。
protected void onDestroy() { super.onDestroy(); mHandler.removeCallbacksAndMessages(null); };
总结:
当我们使用非静态内部类时,如果其实例的持有对象的生命周期大于其外部类对象,那么就有可能导致内存泄露。方案:
- 使用静态的内部类;
- 对所有handler/Runnable中的变量都用弱引用。
关于引用:
? 强引用:如“Object obj = new Object()”,这类引用是Java程序中最普遍的。只要强引用还存在,垃圾收集器就永远不会回收掉被引用的对象。 ? 软引用:它用来描述一些可能还有用,但并非必须的对象。在系统内存不够用时,这类引用关联的对象将被垃圾收集器回收。JDK1.2之后提供了SoftReference类来实现软引用。 ? 弱引用:它也是用来描述非需对象的,但它的强度比软引用更弱些,被弱引用关联的对象只能生存岛下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。在JDK1.2之后,提供了WeakReference类来实现弱引用。 ? 虚引用:最弱的一种引用关系,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的是希望能在这个对象被收集器回收时收到一个系统通知。JDK1.2之后提供了PhantomReference类来实现虚引用。
参考
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1123/2047.html