Handler使用引起内存泄漏分析

Handler使用引起内存泄漏分析

首先我们来看下面一段代码:

public class MainActivity extends Activity {
    private final Handler mHandler = new Handler(){

                @Override
                public void handleMessage(Message msg) {
                    // TODO Auto-generated method stub
                    super.handleMessage(msg);
                }

    };
     @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        mHandler.sendMessageDelayed(Message.obtain(), 60000);  

        // just finish this activity  
        finish();  
    }  

当我们在Activity类中定义一个Handler的内部类时,ADT工具会在旁边有警告显示

This Handler class should be static or leaks might occur 

这表明这样的代码会造成严重的内存泄漏,那么Handler是如何造成内存泄漏的呢?
我们知道当应用程序启动时,UI线程是从Activity Thread运行的,在该类中的main()方法中,已经使用Looper.prepareMainLooper()为该线程添加了Looper对象,这个Looper对象包含一个消息队列MessageQueue,并且能够循环的处理队列中的消息。主线程即UI线程的Looper对象会伴随该应用程序的整个生命周期。

当我们在 UI线程中实例化这个Handler对象时,他就会自动的与线程中Looper的消息对象关联起来,所有发送到消息队列的消息Message都会拥有对handler的引用。而在java中,内部类和匿名类都会保持对外部类的引用。

当finish activity时,里边的延时消息(假如有的话)在得到处理前会一直保存在消息队列中,而且这些message保持对handler的引用,而handler又保持对外部类即activity的引用,这阻止了activity被垃圾回收器回收,从而造成了内存泄漏。

解决此问题正如ADT的提示所说可以讲handler变成静态内部类或者放在另外的文件中,静态内部类不会持有对外部类引用,另外如果我们想要在handler内部去调用外部类Activity,我们可以在handler内部使用弱引用的方式指向所在Activity,这样也不会导致内存泄漏,代码如下所示:

    private MyHandler myHandler = new MyHandler(this);

    private static class MyHandler extends Handler
    {

        private final WeakReference<MainActivity> wActivity;
        public MyHandler(MainActivity activity) {
            super();
            this.wActivity = new WeakReference<MainActivity>(activity);
        }
        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            super.handleMessage(msg);
            MainActivity mainActivity = wActivity.get();
            if(mainActivity!=null)
            {
                //....
            }
        }

    }

但是我们再思考一下,当Activity销毁的时候,那些延时的消息还在队列着,这个情况下这些消息还有没有必要进行处理呢?如果没有必要的话,那需要如何做呢?
查看Handler的API,有几个方法:removeCallbacks(Runnable r)和removeMessages(int what),我们可以在Activity onStop或者onDestroy的时候,取消掉该Handler对象的Message和Runnable。代码如下:

    /**  
  * 一切都是为了不要让mHandler拖泥带水  
  */  
 @Override  
 public void onDestroy() {  
     myHandler.removeMessages(MESSAGE_1);  
     myHandler.removeMessages(MESSAGE_2);  
     myHandler.removeMessages(MESSAGE_3);  
     myHandler.removeCallbacks(mRunnable);
     myHandler.removeCallbacksAndMessages(null); 
     // ... ...  




 }  

经验总结:
1. 注重基础,只有在基础扎实了才能写出健壮的代码
2. 对于adt给出的警告,一定要重视,虽然这些警告并不影响程序的运行,但是这些警告可能会导致程序的崩溃

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值