Handler 引起的内存泄露

移动开发 Android
在编写程序时,一般调用API获取服务器数据时,我们都是采取线程来操作的,这里面就需要用到Handler了,但是需要我们注意的是Handler很可能引起内存的泄露。

先看一组简单的代码

  1. public class SampleActivity extends Activity { 
  2.  
  3.   private final Handler mHandler = new Handler() { 
  4.     @Override 
  5.     public void handleMessage(Message msg) { 
  6.       // ...  
  7.     } 
  8.   } 
  9.   

当我们这样写在一个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对象在主线程中创建的时候,它会关联到Loopermessage queueMessage添加到消息队列中的时候Message会持有当前Handler引用,当Looper处理到当前消息的时候,会调用Handler#handleMessage(Message).
  3. java中,no-static的内部类会 隐式的 持有当前类的一个引用。static的类则没有。

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

  1. public class SampleActivity extends Activity { 
  2.  
  3.   private final Handler mHandler = new Handler() { 
  4.     @Override 
  5.     public void handleMessage(Message msg) { 
  6.       // ... 
  7.     } 
  8.   } 
  9.  
  10.   @Override 
  11.   protected void onCreate(Bundle savedInstanceState) { 
  12.     super.onCreate(savedInstanceState); 
  13.  
  14.     // 发送一个10分钟后执行的一个消息 
  15.     mHandler.postDelayed(new Runnable() { 
  16.       @Override 
  17.       public void run() { } 
  18.     }, 600000); 
  19.  
  20.     // 结束当前的Activity 
  21.     finish(); 
  22.   } 
  23.   

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

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

  1. public class SampleActivity extends Activity { 
  2.  
  3.   /** 
  4.    * 使用静态的内部类,不会持有当前对象的引用 
  5.    */ 
  6.   private static class MyHandler extends Handler { 
  7.     private final WeakReference<SampleActivity> mActivity; 
  8.  
  9.     public MyHandler(SampleActivity activity) { 
  10.       mActivity = new WeakReference<SampleActivity>(activity); 
  11.     } 
  12.  
  13.     @Override 
  14.     public void handleMessage(Message msg) { 
  15.       SampleActivity activity = mActivity.get(); 
  16.       if (activity != null) { 
  17.         // ... 
  18.       } 
  19.     } 
  20.   } 
  21.  
  22.   private final MyHandler mHandler = new MyHandler(this); 
  23.  
  24.   /** 
  25.    * 使用静态的内部类,不会持有当前对象的引用 
  26.    */ 
  27.   private static final Runnable sRunnable = new Runnable() { 
  28.       @Override 
  29.       public void run() { } 
  30.   }; 
  31.  
  32.   @Override 
  33.   protected void onCreate(Bundle savedInstanceState) { 
  34.     super.onCreate(savedInstanceState); 
  35.  
  36.     //  发送一个10分钟后执行的一个消息 
  37.     mHandler.postDelayed(sRunnable, 600000); 
  38.  
  39.     // 结束 
  40.     finish(); 
  41.   } 
  42.   

ok,结束

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

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

NOTE3:具体怎么防止泄漏我也说不清楚,但是Handler 下面有一段源码

  1. final Class<? extends Handler> klass = getClass(); 
  2.             if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && 
  3.                     (klass.getModifiers() & Modifier.STATIC) == 0) { 
  4.                 Log.w(TAG, "The following Handler class should be static or leaks might occur: " + 
  5.                     klass.getCanonicalName()); 
  6.             } 
  7.   
责任编辑:张叶青 来源: eoe Android开发者社区
相关推荐

2015-01-14 13:50:58

AndroidHandler内存泄露

2014-12-18 10:16:00

Java

2012-04-11 13:46:33

ibmdw

2010-06-02 13:00:43

Linux 内存监控

2022-08-26 07:33:49

内存JVMEntry

2022-08-05 11:55:13

FlutteriOS

2009-06-16 11:11:07

Java内存管理Java内存泄漏

2017-12-11 11:00:27

内存泄露判断

2015-05-14 15:38:40

javajava内存泄露

2011-11-17 13:59:41

Java内存管理内存泄露

2016-09-08 16:16:26

iOS移动应用内存泄漏

2015-12-07 09:39:27

Java内存泄露

2017-05-04 16:07:11

Tomcat内存泄露

2022-10-10 11:37:14

Gomap内存

2010-08-10 10:00:57

Flex内存

2011-07-20 17:04:43

Objective-C 内存 内存泄露

2024-04-25 10:06:03

内存泄漏

2010-10-25 10:10:27

ibmdwJava

2010-09-25 11:23:15

Java内存泄露

2021-12-02 07:50:30

NFS故障内存
点赞
收藏

51CTO技术栈公众号