Android Handler造成的内存泄漏的分析j

  在分析之前先补充下java的基本知识,与本文的分析有着重大的联系:java中,非静态(匿名)内部类会默认隐性引用外部类对象,而静态的内部类不会引用外部类对象,注意与静态变量的区别,静态变量是会引用外部类变量的

  在Android中,Handler也是造成内存泄露的一个重要的源头,主要是因为Handler属于TLS(Thread Local Storage)变量,生命周期和Activity是不一致的,因此Handler引用Activity会存在内 存泄露。会造成内存泄露的示例代码:

public class HandlerActivity extends Activity {  
  
    private final Handler mHandler = new Handler() {  
        @Override  
        public void handleMessage(Message 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();  
    }  
  
}  
  在上述代码中,handler所引用的外部类是activity,当activity finish之后,延时消息会继续存在主线程的消息队列中一分钟,然后再处理消息。因为消息引用了activity中的handler(消息中的target变量指向了该handler,即mHandler),而mHandler作为非静态(匿名)内部类,又会默认隐形的引用外部类变量,即对应代码中的activity。这些引用对象会保持到该消息被处理完,这样就导致了该activity对象无法被回收,从而导致了上面说的activity泄露。
  那么上述代码该如何修改呢?可以使用显示的引用,如使用静态内部类(示例代码中还使用了弱引用WeakReference):
public class HandlerActivity2 extends Activity {  
  
    private static final int MESSAGE_1 = 1;  
    private static final int MESSAGE_2 = 2;  
    private static final int MESSAGE_3 = 3;  
    private final Handler mHandler = new MyHandler(this);  
  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        mHandler.sendMessageDelayed(Message.obtain(), 60000);  
  
        // just finish this activity  
        finish();  
    }  
  
    public void todo() {  
    };  
  
    private static class MyHandler extends Handler {  
        private final WeakReference<HandlerActivity2> mActivity;  
  
        public MyHandler(HandlerActivity2 activity) {  
            mActivity = new WeakReference<HandlerActivity2>(activity);  
        }  
  
        @Override  
        public void handleMessage(Message msg) {  
            System.out.println(msg);  
            if (mActivity.get() == null) {  
                return;  
            }  
            mActivity.get().todo();  
        }  
    }  
   当然,也可以将MyHandler写成一个独立的外部类。
   但是上面的代码还不完美,因为当activity finish之后,handler对象还是在message中排队,还是会处理消息。实际上在一般的情况下,activity finish之后,已经没有必要对消息继续处理了,那么该如何优化呢?解决方案也很简单,在activity onStop或者onDestroy的时候,取消掉该handler对象的message和runnable,如这些方法removeCallbacks(Runnable r)和removeMessages(int what),当然也可以简单粗暴一点:
 @Override  
public void onDestroy() {  
    //  If null, all callbacks and messages will be removed.  
    mHandler.removeCallbacksAndMessages(null);  
}  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值