美文网首页Android技术知识Android开发
【转】Android 关于handler引起的内存泄漏

【转】Android 关于handler引起的内存泄漏

作者: 还是桃子好吃 | 来源:发表于2016-11-16 14:31 被阅读0次

日常开发中经常有用到handler,通常的实现方式如下:


Handler handler=new Handler() {

  @Override

  public void handleMessage(Message msg) {

    // ...

  }

};

之前也是一直这么写,但是最近开始看自己写的代码,发现这样写编译器里面有个warning:

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 MessageQueue for a thread other than the main thread, then there is no issue. If the Handler is using the Looper or MessageQueue of the main thread, you need to fix your Handler declaration, as follows: Declare the Handler as a static class; In the outer class, instantiate a WeakReference to the outer class and pass this object to your Handler when you instantiate the Handler; Make all references to members of the outer class using the WeakReference object.

看到这里其实还是不是很懂为什么会引起内存泄漏,那么就从最开始的原理慢慢分析下。

1.当一个Android应用启动的时候,会自动创建一个供应用主线程使用的Looper实例。Looper的主要工作就是一个一个处理消息队列中的消息对象。在Android中,所有Android框架的事件(比如Activity的生命周期方法调用和按钮点击等)都是放入到消息中,然后加入到Looper要处理的消息队列中,由Looper负责一条一条地进行处理。主线程中的Looper生命周期和当前应用一样长。

2.当一个Handler在主线程进行了初始化之后,我们发送一个target为这个Handler的消息到Looper处理的消息队列时,实际上已经发送的消息已经包含了一个Handler实例的引用,只有这样Looper在处理到这条消息时才可以调用Handler#handleMessage(Message)完成消息的正确处理。

3.在Java中,非静态的内部类和匿名内部类都会隐式地持有其外部类的引用。静态的内部类不会持有外部类的引用。

确实上面的代码示例有点难以察觉内存泄露,那么下面的例子就非常明显了

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的finish方法,被延迟的消息会在被处理之前存在于主线程消息队列中10分钟,而这个消息中又包含了Handler的引用,而Handler是一个匿名内部类的实例,其持有外面的SampleActivity的引用,所以这导致了SampleActivity无法回收,进行导致SampleActivity持有的很多资源都无法回收,这就是我们常说的内存泄露。
注意上面的new Runnable这里也是匿名内部类实现的,同样也会持有SampleActivity的引用,也会阻止SampleActivity被回收。
要解决这种问题,思路就是避免使用非静态内部类,继承Handler时,要么是放在单独的类文件中,要么就是使用静态内部类。因为静态的内部类不会持有外部类的引用,所以不会导致外部类实例的内存泄露。当你需要在静态内部类中调用外部的Activity时,我们可以使用弱引用来处理。另外关于同样也需要将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(); 
  }
}

其实在Android中很多的内存泄露都是由于在Activity中使用了非静态内部类导致的,就像本文提到的一样,所以当我们使用时要非静态内部类时要格外注意,如果其实例的持有对象的生命周期大于其外部类对象,那么就有可能导致内存泄露。个人倾向于使用文章的静态类和弱引用的方法解决这种问题。

原文地址:http://droidyue.com/blog/2014/12/28/in-android-handler-classes-should-be-static-or-leaks-might-occur/

相关文章

  • 【转】Android 关于handler引起的内存泄漏

    日常开发中经常有用到handler,通常的实现方式如下: 之前也是一直这么写,但是最近开始看自己写的代码,发现这样...

  • java基础

    Handler怎样防止内存泄漏 handler引起内存泄漏的原因:由于handler的写法问题,如果handler...

  • (转载自diycode)2017 Android 面试题分享整理

    Android(安卓) Android基础知识 Android内存泄漏总结 Handler内存泄漏分析及解决 An...

  • Android 基础

    1、Android布局 2、Android内存泄漏总结 3 、Handler内存泄漏分析及解决 4...

  • 性能优化与保活

    ------内存泄漏优化------Android 内存优化你的 Handler 内存泄露 了吗?Android卡...

  • android学习资料

    第一部分: Android(安卓) Android基础知识 Android内存泄漏总结 Handler内存泄漏分析...

  • Android学习之旅

    1.Android基础知识2.Android内存泄漏总结3.Handler内存泄漏分析及解决4.Android性能...

  • Handler

    一,什么是handler 二,handler的使用 三,handler机制原理 四,handler引起的内存泄漏和...

  • Handler、Looper、message、MessageQu

    最近在写一篇内存泄漏的博客,还在完善中,其中写到handler引起的内存泄漏,发现对Handler了解太过狭隘,于...

  • Android知识体系总结

    第一部分:Android(安卓)Android基础知识Android内存泄漏总结Handler内存泄漏分析及解决H...

网友评论

    本文标题:【转】Android 关于handler引起的内存泄漏

    本文链接:https://www.haomeiwen.com/subject/wplrpttx.html