先看一组简单的代码

1
2
3
4
5
6
7
8
9
public class SampleActivity extends Activity {

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

当我们这样写在一个Activity中时,Android Lint会提示我们这样一个 warning: In Android, Handler classes should be static or leaks might occur.
意思说:在Android中,Handler 类应该是静态的否则可能发生泄漏。

为什么会是这样呢?

了解一下Handler

  1. 当Android程序第一次创建的时候,在主线程同时会创建一个Looper对象。Looper实现了一个简单的消息队列,一个接着一个处理Message对象。程序框架所有主要的事件(例如:屏幕上的点击时间,Activity生命周期的方法等等)都包含在Message对象中,然后添加到Looper的消息队列中,一个一个处理。主线程的Looper存在整个应用程序的生命周期内。
  2. 当一个Handler对象在主线程中创建的时候,它会关联到Looper的 message queue 。Message添加到消息队列中的时候Message会持有当前Handler引用,当Looper处理到当前消息的时候,会调用Handler#handleMessage(Message).
  3. java中,no-static的内部类会 隐式的 持有当前类的一个引用。static的类则没有。

在什么地方引起了内存的泄露呢?再看看下面一段代码

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class SampleActivity extends Activity {

  private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// ...
}
} @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // 发送一个10分钟后执行的一个消息
mHandler.postDelayed(new Runnable() {
@Override
public void run() { }
}, 600000); // 结束当前的Activity
finish();
}
}

Activity结束后,在 Message queue 处理这个Message之前,它会持续存活着。这个Message持有Handler的引用,而Handler有持有Activity(SampleActivity)的引用,这个Activity所有的资源,在这个消息处理之前都不能也不会被回收,所以发生了内存泄露。

解决办法,看下面一段代码

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class SampleActivity extends Activity {

  /**
* 使用静态的内部类,不会持有当前对象的引用
*/
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); /**
* 使用静态的内部类,不会持有当前对象的引用
*/
private static final Runnable sRunnable = new Runnable() {
@Override
public void run() { }
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // 发送一个10分钟后执行的一个消息
mHandler.postDelayed(sRunnable, 600000); // 结束
finish();
}
}

ok,结束

NOTE: 好多人有担心弱引用的Activity回收的情况,这个完全不用担心的,因为我们在这个界面的时候,这个Activity 是不会被回收的,想想 如果我们的这个Activity被回收了,我们的这个界面是怎么存在的呢?

NOTE2: 各位,我是参照AsyncTask ,查看文档和自己的理解,存在我解释不了的地方,还望见谅,如有错误还望见谅。

原文作者: 花_开_堪_折_枝

原文地址: http://my.eoe.cn/yaming/archive/5133.html

Handler 引起的内存泄露的更多相关文章

  1. Android handler 可能会造成内存泄露

    Android handler 可能会造成内存泄露 Android Studio 使用 Handler 时: private Handler handler = new Handler(){ @Ove ...

  2. Android 中 Handler 引起的内存泄露

    在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用.其实这可能导致内存泄露,代码中哪里可能导致内存泄露,又是如何导致内存泄露的呢?那我们就慢慢分析一下.http://w ...

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

    如果您在Activity中定义了一个内部Handler类,如下代码: public class MainActivity extends Activity {       private  Handl ...

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

    很多人面试的时候,都知道Handler 极易造成内存泄露,但是有一些讲不出来为什么,好一点的 会告诉你looper msg 之类的,但是你再往下问 为什么msg持有handler handler为什么 ...

  5. Android中Handler引起的内存泄露

    在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用.通常我们的代码会这样实现. 1 2 3 4 5 6 7 8 9 public class SampleActivit ...

  6. Handler引起的内存泄露

    一般我都写handler的时候是这样的:   public class MyActivity extends Activity{ private final Handler myHandler = n ...

  7. Android中Handler导致的内存泄露

    http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html Consider the follo ...

  8. Android性能优化——之防止内存泄露

    又是好久没有写博客了,一直都比较忙,最近终于有时间沉淀和整理一下最近学到和解决的一些问题. 最近进行技术支持的时候,遇到了几个崩溃的问题,都是OOM异常,一般OOM异常给人的感觉应该是加载大图片造成的 ...

  9. Android之内存泄露、内存溢出、内存抖动分析

      内存   JAVA是在JVM所虚拟出的内存环境中运行的,内存分为三个区:堆.栈和方法区.栈(stack):是简单的数据结构,程序运行时系统自动分配,使用完毕后自动释放.优点:速度快.堆(heap) ...

随机推荐

  1. linux常用的重要的命令: netstat

    Netstat 命令用于显示各种网络相关信息,如网络连接,路由表,接口状态 (Interface Statistics),masquerade 连接,多播成员 (Multicast Membershi ...

  2. java面向对象编程— —第七章 继承

    7.1继承的起源 继承(Inheritance),即在面向对象编程中,可以通过扩展(extends)一个已有的类,并继承该类的属性的行为,来创建一个新的类. 已有的类称为父类(也可以称为基类,超类), ...

  3. 使用MediaRecorder录制音频

    手机一般都提供了麦克风硬件,而Android系统就可以利用该硬件来录制音频了. 为了在Android应用中录制音频,Android提供了MediaRecorder类,使用MediaRecorder录制 ...

  4. Debugger Exception Notification

    --------------------------- Debugger Exception Notification --------------------------- Project PJSP ...

  5. SVN Unable to connect to a repository at URL

    方法一:右键菜单的“TortoiseSVN”->“Settings”->“Save Data”对话框中,点击“Authentication data”旁的“Clear”按钮,清除登录凭证. ...

  6. 赋值运算符、拷贝初始化和this指针

    一.赋值运算符和拷贝构造函数(重载技术) 赋值运算符和拷贝构造函数有编译器默认提供,但如果想做更复杂的事,需要重载. 1.下面用一个简单的例子先区分一下赋值运算符和拷贝构造函数: #include&l ...

  7. 框架之 spring

    spring有两大特性,其一为ioc,其二为aop 1.ioc的理解 ioc为依赖注入,他的好处就是把创建对象的权利交给spring去管理,这样的好处是 将应用程序中的对象解耦,传统的方式程序中的对象 ...

  8. gsoap框架下的onvif程序流程分析

    SOAP_FMAC5 int SOAP_FMAC6 soap_serve(struct soap *soap) { do { unsigned int k = soap->max_keep_al ...

  9. 访问FLASH设备-W25X16

    /************************************* *文件名称:w25x16_spi.c * *功能描述:访问和写入数据到闪存w25x16 * *建立日期:2016-03-1 ...

  10. SharePoint表单和工作流 - Nintex篇(一)

    博客地址 http://blog.csdn.net/foxdave 本篇开始我将带大家去认识一个第三方的表单工作流工具--Nintex. 本篇将对该工具做一些简单的介绍. Nintex公司成立于200 ...