关闭

使用Handler引发内存泄露的改进

293人阅读 评论(0) 收藏 举报
分类:

如果您在Activity中定义了一个内部Handler类,如下代码:

publicclass MainActivity extendsActivity {
 
    private Handler mHandler = newHandler() {
        @Override
        publicvoid handleMessage(Message msg) {
            //TODO handle message...
        }
 
    };
 
    @TargetApi(11)
    @Override
    publicvoid onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mHandler.sendMessageDelayed(Message.obtain(),60000);
 
        //just finish this activity
        finish();
    }
}


然后运行Android Lint工具会有一个内存泄露警告:

This Handler class should be static or leaks might occur (com.example.ta.MainActivity.1)

Issue: Ensures that Handler classes do not hold on to a reference to an outer class
Id: HandlerLeak

In Android, Handler classes should be static or leaks might occur. Messages enqueued on the application thread’s MessageQueue also retain their target Handler. If the Handler is an inner class, its outer class will be retained as well. To avoid leaking the outer class, declare the Handler as a static nested class with a WeakReference to its outer class.

原因是:

  1. 当Android应用启动的时候,会先创建一个应用主线程的Looper对象,Looper实现了一个简单的消息队列,一个一个的处理里面的Message对象。主线程Looper对象在整个应用生命周期中存在。
  2. 当在主线程中初始化Handler时,该Handler和Looper的消息队列关联。发送到消息队列的Message会引用发送该消息的Handler对象,这样系统可以调用 Handler#handleMessage(Message) 来分发处理该消息。
  3. 在Java中,非静态(匿名)内部类会引用外部类对象。而静态内部类不会引用外部类对象。
  4. 如果外部类是Activity,则会引起Activity泄露 。

当Activity finish后,延时消息会继续存在主线程消息队列中1分钟,然后处理消息。而该消息引用了Activity的Handler对象,然后这个Handler又引用了这个Activity。这些引用对象会保持到该消息被处理完,这样就导致该Activity对象无法被回收,从而导致了上面说的 Activity泄露。

要修改该问题,只需要按照Lint提示的那样,把Handler类定义为静态即可,然后通过WeakReference 来保持外部的Activity对象。

privateHandler mHandler = newMyHandler(this);
privatestatic class MyHandler extendsHandler{
    privatefinal WeakReference<Activity> mActivity;
    publicMyHandler(Activity activity) {
        mActivity = newWeakReference<Activity>(activity);
    }
    @Override
    publicvoid handleMessage(Message msg) {
        System.out.println(msg);
        if(mActivity.get() == null) {
            return;
        }
    }
}


所以,当你在Activity中使用内部类的时候,需要时刻考虑您是否可以控制该内部类的生命周期,如果不可以,则最好定义为静态内部类。

本文出自 云在千峰,转载时请注明出处及相应链接。

本文永久链接: http://blog.chengyunfeng.com/?p=468

0
0
查看评论

浅析Handler引起的内存泄漏及解决方法

在进行异步操作时,我们经常会使用到Handler类。最常见的写法如下。 public class MainActivity extends Activity { ...... private Handler mHandler = new Handler() { @...
  • ruancoder
  • ruancoder
  • 2016-09-06 11:52
  • 3447

Handler作为Activity的内部类所引起的内存泄露问题

前天参加某公司的面试,被问到一个关于Handler作为Activity的内部类所引起的内存泄露的问题。虽然当时答上来了,但是还是想在这里记录一下。 问题总共分为两问:         1、Handler作为Activity的内部类...
  • Jason__Young
  • Jason__Young
  • 2017-03-13 23:04
  • 281

Handler防止内存泄露优雅的一种写法

Handler防止内存泄露优雅的一种写法我们都知道在使用Handler来进行消息通讯的时候由于Activity持有Handler的强引用容易导致页面无法回收造成内存泄露的危险。在网上提出了一些解决方案大都是将强引用改为使用WeakReference的弱引用来避免对象无法回收的状况发生。这里本农提供一...
  • qq_15766129
  • qq_15766129
  • 2017-01-20 15:51
  • 396

Activity内部Handler引起内存泄露的原因分析

Since this Handler is declared as an inner class, it may prevent the outer class from being garbage collected. If the Handler is using a Looper or Mes...
  • sun927
  • sun927
  • 2015-01-22 01:18
  • 1968

内部类与内存泄漏(Handler,Runnable)

利用多线程+Handler来完成UI的交互是常见的操作,而匿名Runnable对象的使用也是在多线程使用时常用的,那么使用时会在什么情况下导致内存泄漏的发生呢? 首先看以下的代码: publicclass MainActivity extends Activity { @Overri...
  • yangqiangjob
  • yangqiangjob
  • 2014-05-22 18:55
  • 1359

handler引发内存泄露

本文转自http://www.linuxidc.com/Linux/2013-12/94065.htm 什么是内存泄露? Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收。也就是说,一个对象不被任何...
  • hunanly
  • hunanly
  • 2015-07-16 17:38
  • 365

匿名内部类引起的内存泄露——Handler和Thread

匿名内部类会持有外部类的引用,当内部类进行延时操作的时候,如果外部类是Activity,那么在执行destroy后,并不会被销毁,从而导致内存泄漏
  • bigbangwqf
  • bigbangwqf
  • 2016-05-06 13:23
  • 1661

【内存泄露】由Handler引发的内存泄漏的思考

前面Looper与Handler解析提到过下面这段代码会出现内存泄漏,其实在Android Studio中会提示这个问题: 在编辑器里面会自动将这段代码标出来,我们看看提示信息是什么?This Handler class should be static or leaks might occu...
  • hp910315
  • hp910315
  • 2015-07-26 20:02
  • 3093

Android中使用Handler引发的内存泄露

当一个Android应用启动的时候,会自动创建一个供应用主线程使用的Looper实例。Looper的主要工作就是一个一个处理消息队列中的消息对象。在Android中,所有Android框架的事件(比如Activity的生命周期方法调用和按钮点击等)都是放入到消息中,然后加入到Looper要处理的消息...
  • lee_tianya
  • lee_tianya
  • 2015-02-25 10:02
  • 1935

错误使用Handler引发的内存泄露

原文地址:http://www.2cto.com/kf/201502/378500.html  在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用。通常我们的代码会这样实现。 public class SampleActivity ext...
  • cs494469249
  • cs494469249
  • 2017-09-23 13:11
  • 101
    个人资料
    • 访问:68599次
    • 积分:1533
    • 等级:
    • 排名:千里之外
    • 原创:73篇
    • 转载:31篇
    • 译文:2篇
    • 评论:2条
    最新评论