Context内存泄露:Handler&内部类

之前代码中,我经常会去使用Thread去处理耗时操作,再用Handler去返回到主线程,后面涉及到内存泄露,才知道这里面存在了很大的隐患–内存泄露。

之前,一直以为Context发生内存泄露的几率很小,就不以为意。奈何当Android Lint给出下面的警告时,我收起小觑之心。

In Android, Handler classes should be static or leaks might occur.

这是我的代码:

public class WallPaperActivity extends Activity {

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

Android Lint给出这句话的意思,就是:定义的Handler类应该是一个静态类,不然可能会导致内存泄露。

为什么Hanlder会导致内存泄露呢?

让我们看看代码里做了什么事:

public class WallPaperActivity extends Activity {

 //...
  private final Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      // ...
      imageview.setImagebitmap(bitmap);
    }
  }

}

这边主要进行的是后台线程拉取网络图片的一个操作,然后在主线程中进行更新界面。

这里,我们要知道:当一个Android应用程序第一次启动时,Android框架为应用程序的主线程创建一个Looper对象。一个Looper实现了一个简单的消息队列,在一个循环中处理Message对象。所有主要的应用程序框架事件(如活动生命周期方法调用,单击按钮,等等)都包含在Message对象,它被添加到Looper的消息队列然后一个个被处理。主线程的Looper在应用程序的整个生命周期中存在。而当一个Handle在主线程被实例化,它就被关联到Looper的消息队列。被发送到消息队列的消息会持有一个Handler的引用,以便Android框架可以在Looper最终处理这个消息的时候,调用Handler.handleMessage(Message)。在java中,非静态的内部类和匿名类会隐式的持有一个当前外部类的引用。然而,静态内部类不会。(来自译文)

所以,上面代码中创建handler时,其实该对象已经隐式持有WallPaperActivity的引用了,由于后台在下载拉取图片,可能会很快,可能慢的跟狗一样,这时,在界面关闭之前,加载完图片并显示到界面上,即hanlder处理消息完毕,那自然万事大吉。可是网络不好时,图片下载一半时,Activity关闭,这时,因为线程没执行完,线程中Handler持有WallPaperActivity引用,导致了该Activity无法被回收,这就是泄露的来源。

查找了网络大神等对此的解决方案,总共有两个:

1.根据界面需要去对包含Hanlder的线程进行限制:在关闭Activity(onDestroy())之前停掉线程。显然这是一个方法,不过对我不适合,毕竟我希望图片最好可以下下来的。

2.声明Handler类为静态类:

static class MyHandler extends Handler {
       WeakReference<WallPaperActivity> mActivity;
       MyHandler(WallPaperActivity activity) {  

          mActivity = new WeakReference<WallPaperActivity>(activity);  

       }  

       @Override
       public void handleMessage(Message msg) {  

             WallPaperActivity theActivity = mActivity.get();  

             if(theActivity != null){
              //...
             }
        }
  }  

  MyHandler ttsHandler = new MyHandler(this);  

这里就是按照Android Lint把handler类定义为静态,然后通过WeakReference(弱引用)来保持外部Activity对象。

显然,这后面一种,是我需要的!

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

时间: 2024-11-08 08:11:40

Context内存泄露:Handler&内部类的相关文章

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

原因:匿名内部类会持有外部类的引用,当内部类进行延时操作的时候,如果外部类是Activity,那么在执行destroy后,并不会被销毁,从而导致内存泄漏. Handler: 解决方案: 1.改为静态内部类(静态内部类不持有外部类的引用)+弱引用 private static MyHandler extends Handler { @Override public void handleMessage(Message msg) { //TODO handle message... } }; 但是,

Android Handler内存泄露

前言 在Android开发中,使用Handler的地方很多,大致通常写法如下: private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { if (msg.what == 1) { mAdapter.notifyDataSetChanged(); } }};这段代码看似没什么问题,但是里面却有一个警告,警告信息如下: This Handler class should

Android内存泄露分析和处理

什么是内存泄露 Java使用有向图机制,通过GC自动检查内存中的对象,如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收.也就是说,一个对象不被任何引用所指向,则该对象会在被GC发现的时候被回收. 内存泄露的原因 1.资源对象没关闭造成的内存泄漏 资源性对象比如 (Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存.它们的缓冲不仅存在于 java虚拟机内,还存在于java虚拟机外.如果我们仅仅是把它的引用设置为null

彻底搞懂 Java 内存泄露

Java内存回收方式 Java判断对象是否可以回收使用的而是可达性分析算法. 在主流的商用程序语言中(Java和C#),都是使用可达性分析算法判断对象是否存活的.这个算法的基本思路就是通过一系列名为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的,下图对象object5, object6, object7虽然有互相判断,但它们到GC Roo

Android工具:LeakCanary—内存泄露检测神器

一.LeakCanary简介LeakCanary是Square公司开源的一个检测内存的泄露的函数库,可以方便地和你的项目进行集成,在Debug版本中监控Activity.Fragment等的内存泄露:LeakCanary集成到项目中之后,在检测到内存泄露时,会发送消息到系统通知栏.点击后打开名称DisplayLeakActivity的页面,并显示泄露的跟踪信息,Logcat上面也会有对应的日志输出.同时如果跟踪信息不足以定位时,DisplayLeakActivity还为开发者默认保存了最近7个d

Andoid内存泄露

1 android 内存泄露是因为分配的内存回收失败 public static LocalHelper getInstance(Context context) { if (instance==null){ instance = new LocalHelper(context); } return instance;} 如果在contenx 传一个Activity 那么在Acitivty finish之后是无法对activity 进行回收的因为 静态实例会对activity继续引用, 这时候

JAVA 内存泄露详解(原因、例子及解决)

转载请注明出处:http://blog.csdn.net/anxpp/article/details/51325838,谢谢! Java的一个重要特性就是通过垃圾收集器(GC)自动管理内存的回收,而不需要程序员自己来释放内存.理论上Java中所有不会再被利用的对象所占用的内存,都可以被GC回收,但是Java也存在内存泄露,但它的表现与C++不同. JAVA 中的内存管理 要了解Java中的内存泄露,首先就得知道Java中的内存是如何管理的. 在Java程序中,我们通常使用new为对象分配内存,而

【译】什么导致了Context泄露:Handler&amp;内部类

思考下面代码 1 public class SampleActivity extends Activity { 2 3 private final Handler mLeakyHandler = new Handler() { 4 @Override 5 public void handleMessage(Message msg) { 6 // ... 7 } 8 } 9 } 如果没有仔细观察,上面的代码可能导致严重的内存泄露.Android Lint会给出下面的警告: In Android,

什么导致了Context泄露:Handler&amp;内部类

参考:http://www.cnblogs.com/kissazi2/p/4121852.html 为什么 内部自定义handler类要static类型? 原因: 1.当一个Android应用程序第一次启动时,Android框架为应用程序的主线程创建一个Looper对象.一个Looper实现了一个简单的消息队列,在一个循环中处理Message对象.所有主要的应用程序框架事件(如活动生命周期方法调用,单击按钮,等等)都包含在Message对象,它被添加到Looper的消息队列然后一个个被处理.主线