引言

在Android中如果错误的使用Handler也会引起内存泄漏的。所以在我们实际开发中还是需要多多注意,并尽量去避免它。

原例

Android代码中涉及线程通信的地方,我们基本都会选择使用Handler。比如:

public class HandlerActivity extends Activity{//可能引起内存泄漏的方法private final Handler mHandler = new Handler(){@Overridepublic void handlerMessage(Message msg){//...}}}

如果使用Android Lint分析这段代码的话,会发现提示:

This Handler class should be static or leaks might occur.

 这就是在提醒开发者,这里的写法有可能会引起内存泄漏,需要开发者去处理。那为什么会可能产生内存泄漏呢?这个要从Handler的机制来说,我们都知道Handler是和Looper以及MessageQueue一起使用的。在Android中一个应用启动后,系统会默认创建一个为主线程服务的Looper对象,该对象用于处理主线程的所有Message对象,它的生命周期贯穿于整个应用的生命周期。在主线程中使用的Handler都会默认绑定到这个Looper对象。在主线程中创建Handler对象时,它会立即关联主线程Looper对象的MessageQueue,这时发送到MessageQueue中的Message对象都会持有这个Handler对象的引用,这样在Looper处理消息时才能回调到Handler的handleMessage方法。因此如果Message还没有被处理完成,那么Handler也就不会被垃圾回收。
 在上段代码中,我们将Handler的实例声明为了HandlerActivity的内部类。而在Java中非静态内部匿名类会持有外部类的一个隐式的引用,这样就又能能会导致外部类无法被垃圾回收。因此,最终由于MessageQueue中的Message对象还没有处理完成,就会持有Handler对象的引用,而非静态的Handler对象会持有外部类HandlerActivity的引用,这个Activity无法被垃圾回收,从而导致了内存泄漏。
比如下面这种写法:

public class HandlerActivity extends Activity{//可能引起内存泄漏的方法private final Handler mHandler = new Handler(){@Overridepublic void handlerMessage(Message msg){//...}}@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);//延迟5分钟发送消息mHandler.postDelayed(new Runnable(){@Overridepublic void run(){...}},1000*60*5)}}

由于消息要延后5分钟发送,因此,当用户进入这个Activity并在5分钟内退出后,在消息发送并处理完成之前,这个Activity是不会被系统回收的。
那么要怎么解决呢?有两个方案:

  • 在子线程中使用Handler,这时需要开发者自己创建一个Looper对象,这个Looper对象的生命周期同一般的Java对象,因此这种用法没有问题。
  • 将Handler声明为静态的内部类,前面说过,静态内部类不会持有外部类的引用,因此,也不会引起内存泄漏。

正确用法

所以,下面我们看下经典的用法:

public class HandlerActivity extends Activity{//声明一个静态的Handler内部类,并持有外部类的弱引用private static class InnerHandler extends Handler{private final WeakReference mActivity;public InnerHandler(HandlerActivity activity){mActivity = new WeakReference(activity);}@Overridepublic void handleMessage(Message msg){HandlerActivity activity = mActivity.get();if(activity != null){//...}}}private final InnerHandler mHandler = new InnerHandler(this);//静态的匿名内部类不会持有外部类的引用private static final Runnable sRunnable = new Runnable(){@Overridepublic void run(){//...}}@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);//延迟5分钟发送消息mHandler.postDelayed(sRunnable,1000*60*5);}}

更多相关文章

  1. android launcher的结构
  2. Android系列之Intent传递对象的几种实例方法
  3. [转]五大布局对象---FrameLayout,LinearLayout ,AbsoluteLayout,
  4. [置顶] android 耳机按钮深层理解
  5. Android(安卓)从原型模式看java实例化对象clone和new的区别
  6. android 内存优化详解
  7. android中常见的内存溢出和解决办法
  8. 关于Android中使用Handler造成内存泄露的分析和解决
  9. Android(安卓)判定网络连接状态 以及监听网络链接状态的变化

随机推荐

  1. Android(安卓)Dalvik虚拟机概述
  2. 零碎知识点回顾——常用数据结构
  3. OpenCV移动端之android JNI
  4. XX学院Android VIP视频教程
  5. Android之Layout资源文件
  6. 美团外卖Android(安卓)Lint代码检查实践
  7. Android中保存数据常用的方法
  8. 课堂小结
  9. Android系统启动顺序(按下power键后所做
  10. 3G应用开发之Android(安卓)传智播客 基础