The handler class should be static or leaks might occur原因及解决方法

翻译自http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html

在主线程中使用Handler对象,比如下面的代码

public class SampleActivity extends Activity {

  private final Handler mLeakyHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      // ...
    }
  }
}

这段代码会产生隐秘的内存溢出的错误,Android Lint会给出羡慕的警告:

The handler class should be static or leaks might occur.

但是究竟哪一部分内存会在什么情况下溢出呢?

要解决这一问题需要了解一下安卓系统背景知识:

1. 当一个Android应用启动的时候,Android系统为这个应用的主线程创建一个Looper对象。Looper对象实现了简单的消息队列(message queue),依次处理循环(Looper)中的消息。所有的主要应用事件(比如Activity的生命周期,按钮的点击等)都被包裹为一个消息(Message)实体,被添加到Looper的消息队列中依次处理。主线程的Looper在应用的整个生命周期中都存在。

2.当一个Handler对象在主线程中初始化时,它被关联到Looper的消息队列中。在Handler的sendMessage()方法被调用的时候,一个Message对象会被发往Looper的消息队列中,被发送到消息队列中的Message将会持有Handler的引用,然后系统才能在Looper处理Message时调用Handler对象的handleMessage(Message)方法。

3.在Java中,非静态(non-static)内部和匿名类将会持有外部类的引用。相反,静态的内部类不会持有外部类的引用。

更多Looper,Handler相关的知识可以在文后链接的博客中找到。

了解了这些背景之后我们来看一下内存在什么情况下溢出,首先看下面一段代码:

public class SampleActivity extends Activity {

  private final Handler mLeakyHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      // ...
    }
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Post a message and delay its execution for 10 minutes.
    mLeakyHandler.postDelayed(new Runnable() {
      @Override
      public void run() { /* ... */ }
    }, 1000 * 60 * 10);

    // Go back to the previous Activity.
    finish();
  }
}

当Activity结束的时候,被延迟的Message会继续存活在主线程中10分钟,直到它被处理了。这个Message持有Activity的Handler对象的引用,同时Handler是Activity的非静态(non-static)匿名内部类,所以Handler持有外部类也就是Activity的引用。这样的引用关系会阻止Activity被Java GC回收,释放系统持有的资源,直到Message被处理了。另外杨的引用对于匿名Runnable()对象也存在。

解决这个问题的方法可以有:在一个新的文件中继承Handler类,或者使用一个静态内部类。静态内部类不会持有外部类的引用,所以Activity不会被泄露。如果需要在Handler中调用外部类(此处为Activiity)的方法,可以使Handler拥有Activity的弱引用(WeakReference),这样就不会意外地泄露Activity。

为了解决实例化内部匿名Runnable类时导致的内存泄漏的问题,我们可以使内部匿名Runnable类变为外部类的静态对象。

public class SampleActivity extends Activity {

  /**
   * Instances of static inner classes do not hold an implicit
   * reference to their outer class.
   */
  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) {
        // ...
      }
    }
  }

  private final MyHandler mHandler = new MyHandler(this);

  /**
   * Instances of anonymous classes do not hold an implicit
   * reference to their outer class when they are "static".
   */
  private static final Runnable sRunnable = new Runnable() {
      @Override
      public void run() { /* ... */ }
  };

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Post a message and delay its execution for 10 minutes.
    mHandler.postDelayed(sRunnable, 1000 * 60 * 10);

    // Go back to the previous Activity.
    finish();
  }
}

在Activity中实例化内部类时,如果内部类可以在Activity的生命周期之外继续存活于哦,那么这样的内部类不能为非静态的。这种情况应该使用静态内部来并且持有外部类对象的弱引用。

相关链接:

http://www.cnblogs.com/codingmyworld/archive/2011/09/12/2174255.html

时间: 2024-10-13 02:32:35

The handler class should be static or leaks might occur原因及解决方法的相关文章

This Handler class should be static or leaks might occur

Android中,在使用到Handler的时候,如果按如下代码编写: private Handler handler; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); handler = new Handler() { @Override public void handleMessage(Message msg) { // TODO Auto-gene

This Handler class should be static or leaks might occur(null) 解决办法

首先解释下这句话This Handler class should be static or leaks might occur,大致意思就是说:Handler类应该定义成静态类,否则可能导致内存泄露. 具体如何解决,在国外有人提出,如下: Issue: Ensures that Handler classes do not hold on to a reference to an outer class In Android, Handler classes should be static

Android - This Handler class should be static or leaks might occur.

今天学习了使用 HTTP协议,从Android客户端往Tomcat服务器端以GET发送请求,途中无意中发现自己写的Handler类被Android提示:This Handler class should be static or leaks might occur. 往google上type,发现很多网友都做了解释,也感触颇深,编译器的提示,有时真的要留意,这对自己学习也有很大的帮助. 虽然多了几行代码,但为了实用,我就上贴自己实际点的例子,Activity: package spt.http.

This Handler class should be static or leaks might occur,Handler和Context使用的注意事项!

Android中.在使用到Handler的时候,假设按例如以下代码编写: private Handler handler; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); handler = new Handler() { @Override public void handleMessage(Message msg) { // TODO Auto-ge

Handler Class Should be Static or Leaks Occur

在使用Handler更新UI的时候,我是这样写的: public class SampleActivity extends Activity {   private final Handler mLeakyHandler = new Handler() {     @Override     public void handleMessage(Message msg) {       // TODO     }   } } 看起来很正常的,但是 Android Lint 却给出了警告: This

Cannot make a static reference to the non-static method的解决方法

报错原因:在一个类中写了一个public String getContent()方法和一个main()方法,getContent()方法中包含了getClass()方法,在main()方法中直接调用了getContent()就出现如题的错误.这样一样 解决方法:先实例化类,然后再调用getContent()就没有问题了 1 GetProperties gp = new GetProperties(); 2 String s = gp.getCotent(); 这样一来都不要加static了 说明

【Android】[转] Android Handler应设为static

android开发中,使用Lint检测时会提示这么一句话 : This Handler class should be static or leaks might occur.意为handler应用static修饰否则容易发生内存泄漏. ADT20有这么一个变化:Look for handler leaks: This check makes sure that a handler inner class does not hold an implicit reference to its ou

Handler警告以及解决方法

在项目中使用Handler时,会出现警告提示,也会在Problems中进行统计和显示,如下图: 把鼠标放在,就会提示This Handler class should be static or leaks might occur,如下: @SuppressLint("HandlerLeak") private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { };

Handler Should be static or leaks Occur?

解决办法: public class SampleActivity extends Activity { /** * Instances of static inner classes do not hold an implicit * reference to their outer class. */ private static class MyHandler extends Handler { private final WeakReference<SampleActivity> mA