转自android handler的警告Handler Class Should be Static or Leaks Occur

在使用Handler更新UI的时候,我是这样写的:

public class SampleActivity extends Activity {private final Handler mLeakyHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {// TODO}}
}

看起来很正常的,但是 Android Lint 却给出了警告:

This Handler class should be static or leaks might occur

意思是说:这个Handler必须是static的,否则就会引发内存泄露。

其实,对于这个问题,Android Framework 的工程师 Romain Guy 早已经在Google论坛上做出过解释,并且给出了他的建议写法:

I wrote that debugging code because of a couple of memory leaks I
found in the Android codebase. Like you said, a Message has a
reference to the Handler which, when it’s inner and non-static, has a
reference to the outer this (an Activity for instance.) If the Message
lives in the queue for a long time, which happens fairly easily when
posting a delayed message for instance, you keep a reference to the
Activity and “leak” all the views and resources. It gets even worse
when you obtain a Message and don’t post it right away but keep it
somewhere (for instance in a static structure) for later use.

他的建议写法是:

class OuterClass {class InnerClass {private final WeakReference<OuterClass> mTarget;InnerClass(OuterClass target) {mTarget = new WeakReference<OuterClass>(target);}void doSomething() {OuterClass target = mTarget.get();if (target != null) {target.do();    }}
}

下面,我们进一步解释一下:

  • Android App启动的时候,Android Framework 为主线程创建一个Looper对象,这个Looper对象将贯穿这个App的整个生命周期,它实现了一个消息队列(Message Queue),并且开启一个循环来处理Message对象。而Framework的主要事件都包含着内部Message对象,当这些事件被触发的时候,Message对象会被加到消息队列中执行。
  • 当一个Handler被实例化时(如上面那样),它将和主线程Looper对象的消息队列相关联,被推到消息队列中的Message对象将持有一个Handler的引用以便于当Looper处理到这个Message的时候,Framework执行Handler的handleMessage(Message)方法。
  • 在 Java 语言中,非静态匿名内部类将持有一个对外部类的隐式引用,而静态内部类则不会。

到底内存泄露是在哪里发生的呢?以下面代码为例:

public class SampleActivity extends Activity {              private final Handler mLeakyHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {// ...}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// Post a message and delay its execution for 10 minutes.mLeakyHandler.postDelayed(new Runnable() {@Overridepublic void run() { }}, 60 * 10 * 1000);// Go back to the previous Activity.finish();}
}

当Activity被finish()掉,Message将存在于消息队列中长达10分钟的时间才会被执行到。这个Message持有一个对Handler的引用,Handler也会持有一个对于外部类(SampleActivity)的隐式引用,这些引用在Message被执行前将一直保持,这样会保证Activity的上下文不被垃圾回收机制回收,同时也会泄露应用程序的资源(views and resources)。

为解决这个问题,下面这段代码中的Handler则是一个静态匿名内部类。静态匿名内部类不会持有一个对外部类的隐式引用,因此Activity将不会被泄露。如果你需要在Handler中调用外部Activity的方法,就让Handler持有一个对Activity的WeakReference,这样就不会泄露Activity的上下文了,如下所示:

public class SampleActivity extends Activity {     /*** Instances of static inner classes do not hold an implicit* reference to their outer class.*/private static class MyHandler extends Handler {private final WeakReference<SampleActivity> mActivity;public MyHandler(SampleActivity activity) {mActivity = new WeakReference<SampleActivity>(activity);}@Overridepublic void handleMessage(Message msg) {SampleActivity activity = mActivity.get();if (activity != null) {// ...}}
}private final MyHandler mHandler = new MyHandler(this);      /*** Instances of anonymous classes do not hold an implicit* reference to their outer class when they are "static".*/private static final Runnable sRunnable = new Runnable() {@Overridepublic void run() { }};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// Post a message and delay its execution for 10 minutes.mHandler.postDelayed(sRunnable, 60 * 10 * 1000);// Go back to the previous Activity.finish();}
}

总结:
在实际开发中,如果内部类的生命周期和Activity的生命周期不一致(比如上面那种,Activity finish()之后要等10分钟,内部类的实例才会执行),则在Activity中要避免使用非静态的内部类,这种情况,就使用一个静态内部类,同时持有一个对Activity的WeakReference。

Android应用开发—如何解决handler的警告:Handler Class Should be Static or Leaks Occur相关推荐

  1. 85、android handler的警告Handler Class Should be Static or Leaks Occur

    转载:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1106/1922.html 在使用Handler更新UI的时候,我是这样写 ...

  2. Android项目开发实战—倒计时[Handler,Timer,TimerTask,Message]

    Android实现倒计时 先上一个本人实际操作中的界面: 源代码: (activity_main.xml和MainActivity.java) activity_main.xml: <Linea ...

  3. android之lint警告This Handler class should be static or leaks might occur

    更新到adt2.0的开发者们可能会在handler上发现这么一条警告:This Handler class should be static or leaks might occur . 首先在ADT ...

  4. Android Studio开发RecyclerView遇到的各种问题以及解决(一)

    Android Studio开发RecyclerView遇到的各种问题以及解决(一) 参考文章: (1)Android Studio开发RecyclerView遇到的各种问题以及解决(一) (2)ht ...

  5. 【Android 应用开发】Android中使用ViewPager制作广告栏效果 - 解决ViewPager占满全屏页面适配问题

    . 参考界面 : 携程app首页的广告栏, 使用ViewPager实现        自制页面效果图 : 源码下载地址: http://download.csdn.net/detail/han1202 ...

  6. android studio socket 失败,Android应用开发Android Studio建立Socket连接失败解决方法

    本文将带你了解Android应用开发Android Studio建立Socket连接失败解决方法,希望本文对大家学Android有所帮助. < Android Studio建立Socket连接失 ...

  7. Android插件化开发之解决OpenAtlas组件在宿主的注冊问题

    Android插件化开发之解决OpenAtlas组件在宿主的注冊问题 OpenAtlas有一个问题,就是四大组件必须在Manifest文件里进行注冊,那么就必定带来一个问题,插件中的组件都要反复在宿主 ...

  8. Android实际开发中的bug总结与解决方法(一)

    Android实际开发中的bug总结与解决方法(一) 参考文章: (1)Android实际开发中的bug总结与解决方法(一) (2)https://www.cnblogs.com/ywq-come/p ...

  9. android程序突然崩溃如何调试,Android应用开发android 调试崩溃Unable to instantiate application的解决方法...

    本文将带你了解Android应用开发android 调试崩溃Unable to instantiate application的解决方法,希望本文对大家学Android有所帮助. 更新后Android ...

最新文章

  1. c语言中struct和c++中class实例对比
  2. python基础04
  3. Android Material各种颜色设置
  4. Maven编译项目时报错:不再支持源选项 5。请使用 6 或更高版本。 不再支持目标选项 1.5。请使用 1.6 或更高版本。
  5. 微服务面试 - 微服务简单介绍
  6. Python写数据结构:二叉树的创建和遍历
  7. Colab+Google使用教程
  8. 贝叶斯小数据分析—— 23 条数据决定宇航员生死(使用 PyMC3)
  9. 医疗器械安全知识小科普
  10. 无盘服务器内存回写速度,网吧文化监管平台异常频繁回写数据导致无盘客户机游戏秒卡,打字卡...
  11. LaTeX 旁注 边注 Marigin Note
  12. php手机模板修改,pc和手机模板自动切换
  13. 一些电子资源的分享(1)
  14. teracopy php,Unraid 升级到 UnRaid 6.0的详细操作步骤(三)
  15. 分布式任务调度系统设计:详解Go实现任务编排与工作流
  16. echats实现进度条、饼状图、折线图、柱状图、柱状图和折线图的集合体
  17. 战地之王Awesonmium
  18. JAVASCRIPT中THIS指的是什么?
  19. 数据分析:单元1 NumPy库入门
  20. 【精选实践】爱奇艺实用数据库选型树:不同场景如何快速选择数据库?

热门文章

  1. springcloud阿里巴巴五大组件_如何无缝迁移 SpringCloud/Dubbo 应用到 Serverless 架构
  2. python每天定时9点执行_python定时器每天订时执行的实例方法
  3. C++for_each| bind1st | ptr_fun | std::function的用法
  4. 苦逼的程序员怎么发展
  5. CentOS7的yum安装mysql
  6. iView学习笔记(三):表格搜索,过滤及隐藏列操作
  7. c++primer plus笔记
  8. Docker 二进制安装docker
  9. 部署WEB项目到服务器(三)安装mysql到linux服务器(Ubuntu)详解
  10. linux之SQL语句简明教程---SUBSTRING