Android开发——Handler引起的内存泄露

在Android异步消息处理中,

    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            //
        }
    };

但当我们这么写时,编译器会给出警告提示:Handler类应该是静态的,可能发生内存泄漏。

原因:

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

这里Handler是一个匿名内部类的实例,其持有外面的Activity的引用,所以当Handler伴随一个耗时后台线程时就会出现Activity无法回收,进而内存泄露。

解决方法:

一:将Handler声明为静态内部类。

因为静态的内部类不会持有外部类的引用,所以不会导致外部类实例的内存泄露。由于Handler不再持有外部类对象的引用了,导致程序不允许你在Handler中操作Activity中的对象。所以如果要在静态内部类中调用外部的Activity时,我们使用弱引用来处理(WeakReference)。

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) {
        // ...
      }
    }
  }

二:postDelayed(new Runnable(),10000)情况

   mHandler.postDelayed(new Runnable() {
      @Override
      public void run() {
    //
    }
    }, 10000);

在handler的post方法中我们加入了一个匿名的runnable,同时我将其执行延迟了10秒。

被延迟的消息会在被处理之前一直存在于主线程消息队列中。同时new Runnable也是匿名内部类实现的,同样也会持有Activity的引用。

这时候我们还需要将Runnable设置为静态的成员属性。

private static final Runnable sRunnable = new Runnable() {
      @Override
      public void run() { /* ... */ }
  };

同时onCreate()中mHandler.postDelayed(sRunnable, 10000);

另一个方法是使用Handler的removeCallbacksAndMessages ()方法,把消息对象从消息队列移除。

当参数为null的时候,可以清除掉所有跟次handler相关的Runnable和Message,我们在onDestroy中调用次方法清理掉所有Messages。

    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacksAndMessages(null);
    };

总结:

当我们使用非静态内部类时,如果其实例的持有对象的生命周期大于其外部类对象,那么就有可能导致内存泄露。方案:

  • 使用静态的内部类;
  • 对所有handler/Runnable中的变量都用弱引用。

关于引用:

    ?   强引用:如“Object obj = new Object()”,这类引用是Java程序中最普遍的。只要强引用还存在,垃圾收集器就永远不会回收掉被引用的对象。
    ?   软引用:它用来描述一些可能还有用,但并非必须的对象。在系统内存不够用时,这类引用关联的对象将被垃圾收集器回收。JDK1.2之后提供了SoftReference类来实现软引用。
    ?   弱引用:它也是用来描述非需对象的,但它的强度比软引用更弱些,被弱引用关联的对象只能生存岛下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。在JDK1.2之后,提供了WeakReference类来实现弱引用。
    ?   虚引用:最弱的一种引用关系,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的是希望能在这个对象被收集器回收时收到一个系统通知。JDK1.2之后提供了PhantomReference类来实现虚引用。

参考

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1123/2047.html

http://blog.csdn.net/ns_code/article/details/18076173

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-08 09:41:18

Android开发——Handler引起的内存泄露的相关文章

Android中Handler引起的内存泄露

在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用.通常我们的代码会这样实现. 但是,其实上面的代码可能导致内存泄露,当你使用Android lint工具的话,会得到这样的警告 In Android, Handler classes should be static or leaks might occur, Messages enqueued on the application thread’s MessageQueue also retain their t

Android 中 Handler 引起的内存泄露

在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用.其实这可能导致内存泄露,代码中哪里可能导致内存泄露,又是如何导致内存泄露的呢?那我们就慢慢分析一下.http://www.jinhusns.com/Products/Download/?type=xcj 在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用.通常我们的代码会这样实现. public class SampleActivity extends Activity {   

Android中Handler导致的内存泄露

http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html Consider the following code: 1 2 3 4 5 6 7 8 9 public class SampleActivity extends Activity { private final Handler mLeakyHandler = new Handler() { @Override public voi

Android OOM(Out of memory) 内存泄露基本知识

Android OOM(Out of memory) 内存泄露基本知识 转载至:http://blog.csdn.net/emilychai2010/article/details/12710135 1. 内存泄露 2. Android里的垃圾回收 3. Heap 4. 调试 5. 常见的内存泄露 1.什么是内存泄露(memory leak)? A "memory leak" in your code is when you keep a reference to an object

Android 从java字节码告诉你 为什么Handler会造成内存泄露

很多人面试的时候,都知道Handler 极易造成内存泄露,但是有一些讲不出来为什么,好一点的 会告诉你looper msg 之类的,但是你再往下问 为什么msg持有handler handler为什么 持有activity'的引用的时候 他们就答不出来了.这里我通过几个简单的例子 和极少部分的源码 来帮助大家彻底理解这一个流程. 那首先 我们来看一个例子,首先定义1个外部类 一个内部类: 1 package com.test.zj; 2 3 public class OuterClass { 4

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

转载请注明出处:http://blog.csdn.net/allen315410/article/details/43638373 本文翻译自:国外某位开发者的博客How to Leak a Context: Handlers & Inner Classes,英文可以的朋友可以直接点击原文查看. 在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用.通常我们的代码会这样实现. public class SampleActivity extends Activity

【转】内部Handler类引起内存泄露

如果您在Activity中定义了一个内部Handler类,如下代码: public class MainActivity extends Activity {       private  Handler mHandler = new Handler() {         @Override         public void handleMessage(Message msg) {             //TODO handle message...         }       

android 开发Handler源码剖析

Android的消息机制主要是Handler的运行机制,而讲Handler的机制,又需要和MessageQueue和Looper结合.MessageQueue中文意思是消息队列,虽说叫队列,但是其内部结构并不是队列组成的,而是采用了单链表的形式来存储消息.MessageQueue只是负责存储消息,并不处理消息(这里指消息的轮训),Looper刚好弥补了这个空缺.我在知道,Handler创建的时候,会默认为我们创建一个Looper对象,那么如何获取当前的Looper呢,这里就使用到了一个Thead

android:布局、绘制、内存泄露、响应速度、listview和bitmap、线程优化以及一些优化的建议!

1.布局优化 首先删除布局中无用的控件和层级,其次有选择地使用性能较低的viewgroup,比如布局中既可以使用RelativeLayout和LinearLayout,那我们就采用LinearLayout,因为RelativeLayout的功能比较复杂,它的布局需要花费 风度哦的CPU实际. 布局优化的另一个手段就是采用<include>,<merge>,<viewstub>标签.<include>主要用于布局重用,<include>,<m