`

内部Handler类引起内存泄露

 
阅读更多

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MainActivity extends Activity {
 
    private  Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            //TODO handle message...
        }
 
    };
 
    @TargetApi(11)
    @Override
    public void 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对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private Handler mHandler = new MyHandler(this);
private static class MyHandler extends Handler{
    private final WeakReference<Activity> mActivity;
    public MyHandler(Activity activity) {
        mActivity = new WeakReference<Activity>(activity);
    }
    @Override
    public void handleMessage(Message msg) {
        System.out.println(msg);
        if(mActivity.get() == null) {
            return;
        }
    }
}

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

 

分享到:
评论

相关推荐

    Android中Handler引起的内存泄露问题解决办法

    在本文中,我们将深入探讨一个特定的内存泄露场景:由Handler引起的内存泄露,以及如何解决这个问题。 首先,我们需要理解Handler在Android中的作用。Handler是Android异步消息处理机制的关键组件,它与Looper和...

    Android 中Handler引起的内存泄露

    本文将深入探讨Android中Handler引起的内存泄露问题,以及如何避免这些问题。 1. **Handler与内存泄露的关系** 当我们创建一个Handler实例时,它会与当前线程的Looper关联。对于主线程,这个Looper是与应用程序的...

    Android开发最常见的5大内存泄漏

    四、匿名内部类和非静态内部类引用导致的内存泄漏 非静态内部类会隐式持有对外部类的引用,如果外部类是一个Activity,当Activity销毁时,由于内部类的引用,导致Activity无法被垃圾回收。为避免这种问题,可以将...

    Android开发最常见的5大内存泄漏.docx

    3. Handler引起的内存泄漏: 当Handler与Activity关联时,如果Handler中的消息队列中有未处理的消息,即使Activity已经销毁,Handler仍然会保持对Activity的引用,导致内存泄漏。解决方法是在Activity的onDestroy()...

    内存泄露的例子分析1

    内存泄露是Android应用开发中的一个重要问题,它会...通过理解静态变量和非静态内部类如何引起内存泄露,以及采取适当的解决策略,如使用弱引用和正确的Context管理,可以有效地防止内存泄露,提高应用的稳定性和性能。

    Android内存优化——常见内存泄露及优化方案

    1. 使用弱引用(WeakReference/SoftReference):对于可能引起内存泄露的对象,可考虑使用弱引用或软引用,以便在内存不足时自动回收。 2. 避免在静态变量或单例中持有Context:尽量使用Application Context,而不是...

    Android 内存泄露

    5. Handler引起的内存泄漏:Handler与Message之间的引用可能导致非静态Handler实例的Activity或Service无法被回收,尤其是Message未被及时处理时。 预防内存泄漏的方法: 1. 避免长时间持有Activity引用,确保引用...

    常见的内存泄漏原因及解决方法 - 简书1

    3. Handler引起的内存泄漏 Android中的Handler常用于线程间通信,但如果不正确处理,也可能导致内存泄漏。Handler会持有创建它的Looper和MessageQueue的引用,而Looper又持有创建它的线程(通常是主线程)的引用。...

    AvoidMemoryLeaksDemo:关于引用context与handler可能导致内存泄露问题写的一份demo

    本文将深入探讨如何避免由Context和Handler引起的内存泄漏,通过"AvoidMemoryLeaksDemo"这个示例项目来讲解相关的知识点。 首先,我们要理解Context在Android中的角色。Context是Android系统的核心组件之一,它是...

    内存泄露从入门到精通三部曲之常见原因与用户实践1

    3. 使用WeakReference或SoftReference管理可能引起内存泄露的对象。 4. 注意线程的生命周期管理,避免长时间运行的任务。 5. 对于回调接口,添加和移除操作要平衡,避免只add不remove。 6. 在退出页面或组件时,确保...

    Android内存泄漏解决方案

    - 使用静态内部类创建Handler,避免非静态内部类持有外部Activity的引用。 #### 五、总结 通过以上步骤,我们可以有效地识别并解决Android应用中的内存泄漏问题。利用MAT插件和其他工具,开发者能够更精确地定位...

    Android_内存泄漏研究及调试.doc )

    #### 二、Android (Java) 中常见的容易引起内存泄漏的不良代码 在Android应用开发中,不当的内存管理可能导致内存泄漏。下面列举了一些常见的内存使用不当的情况: ##### (一) 查询数据库没有关闭游标 **描述**:...

    5.初级面试专题(中小厂).docx

    1. 静态内部类和非静态内部类的区别引起的内存泄漏 2. Handler 引起的内存泄漏 3. 静态集合类引起的内存泄露 4. 单例模式引起的内存泄漏 解决方法包括: 1. 使用 Context 是 ApplicationContext,可以避免内存泄漏...

    HandlerDemo.zip

    - 使用静态内部类+弱引用的方式创建`Handler`,以防止内存泄漏。静态内部类不会持有对外部类的引用,弱引用也不会阻止对象被垃圾回收。 - 对于长生命周期的任务,考虑使用`AsyncTask`、`IntentService`或`LiveData`...

    Android 内存泄漏调试经验分享

    #### 二、Android(Java)中常见的容易引起内存泄漏的不良代码 ##### (一) 查询数据库没有关闭游标 当在Android中执行SQL查询操作时,如果没有正确关闭游标(`Cursor`),则可能导致内存泄漏。这是因为`Cursor`对象...

    5个Android开发中比较常见的内存泄漏问题及解决办法

    3. **Handler引起的内存泄漏** Handler通常用于异步消息处理,但如果在Activity中创建了一个Handler,并且Handler的Looper与主线程的Looper关联,那么Handler会持有Activity的引用,导致Activity无法被垃圾回收。...

    Android内存泄漏终极解决篇(下)

    资源未关闭也会引起内存泄漏,比如文件流、数据库连接、Cursor等。当不再需要这些资源时,必须确保它们被正确关闭。忘记关闭资源会导致系统无法释放相关的内存和资源,影响应用性能。在使用完资源后,应该立即调用`...

Global site tag (gtag.js) - Google Analytics