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

转自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。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/450035.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从远程(包括ftp,http等协议)地址获取文件流信息

URL url new URL("ftp://172.18.251.155:8010/recordsImg/2019-01-28/000008_1548649813267.jpg"); MultipartFile multipartFile new MockMultipartFile(fileName,fileName,"", url.openStream());转载于:https://www.cnblogs.com/baihaojie/p/10331134…

shell 数组

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1&#xff09;定义数组&#xff1a; my_array(1 2 3 4) 也可这样赋值&#xff1a;my_array[4]爱 读取&#xff1a; echo ${my_array[2]…

nodejs 实现文件拷贝

通过4中不通的方式实现对一个文件的拷贝 方式一&#xff1a;readFile 异步一次性读取文件再写入 //异步形式读取文件 function copyFile(url){const extName path.extname(url)const fileName path.basename(url)const dirName path.dirname(url)fs.readFile(url, (err, dat…

国家部委对4G调研:未定给中电信联通发放牌照

一场有关4G牌照发放的论战正在发酵&#xff0c;矛盾的核心在于&#xff0c;除了中移动外&#xff0c;政府是否也会向中电信和联通发放TD-LTE(中国主导的4G标准)牌照 记者 王云辉 雍忠玮 一场围绕4G的新博弈已经白热化。 “多个国家部委正在对4G展开全面调研&#xff0c;但最终如…

Luogu4735 最大异或和

题目蓝链 Description 给你一个序列&#xff0c;你需要支持以下两个操作&#xff1a; A x: 在序列尾部添加一个整数\(x\)&#xff0c;序列的长度增加\(1\)Q l r x: 询问操作&#xff0c;你需要找到一个位置\(p \in [l, r]\)&#xff0c;使得&#xff1a;\(x \bigoplus a_p \big…

Spring-jdbc:JdbcTemplate使用简介

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 为了使 JDBC 更加易于使用,Spring 在 JDBCAPI 上定义了一个抽象层, 以此建立一个JDBC存取框架. 作为 SpringJDBC 框架的核心, JDBC 模板…

Java多线程编程:变量共享分析(Thread)

Java多线程编程&#xff1a;变量共享分析&#xff08;Thread&#xff09; Java 创建线程的两种方法 此处只简单讲下自己对java多线程变量共享的理解&#xff1a; 按照进程和多线程的原理&#xff0c;同一进程内的多个线程之间的地址空间是共享的&#xff08;除去ThreadLocal&a…

嘉益仕(Litns)带您读懂MES系统:选型篇

自从智能制造概念提出以来&#xff0c;制造执行系统MES在国内掀起了新一波的热潮。众多企业在技术发展、政策导向和自身需要的推动下&#xff0c;纷纷上马MES请添加链接描述项目。 由此也带动了MES软件开发企业的快速发展。一夜之间MES软件开发企业遍地开花&#xff0c;MES产品…

[WPF]xml序列化以及反序列化数据

代码 XML序列化工具类 public static class XMLHelper{/// <summary>/// 将对象序列化为指定的文件名/// </summary>/// <typeparam name"T"></typeparam>/// <param name"obj"></param>/// <param name"fil…

多线程的那点儿事

1. 多线程的那点儿事&#xff08;基础篇&#xff09; 多线程编程是现代软件技术中很重要的一个环节。要弄懂多线程&#xff0c;这就要牵涉到多进程&#xff1f;当然&#xff0c;要了解到多进程&#xff0c;就要涉及到操作系统。不过大家也不要紧张&#xff0c;听我慢慢道来。…

Android应用开发—AsyncTask

摘录自 Android 多线程—–AsyncTask详解 AsyncTask AsyncTask&#xff1a;异步任务&#xff0c;从字面上来说&#xff0c;就是在我们的UI主线程运行的时候&#xff0c;异步的完成一些操作。AsyncTask允许我们的执行一个异步的任务在后台。我们可以将耗时的操作放在异步任务当…

std::shared_ptr之deleter的巧妙应用

本文由作者邹启文授权网易云社区发布。std::shared_ptr一次创建&#xff0c;多处共享&#xff0c;通过引用计数控制生命周期。 实例 在邮箱大师PC版中&#xff0c;我们在实现搜索时&#xff0c;大致思路是这样的&#xff1a; 每一个账号都有一个SearchFlow&#xff0c;搜索开始…

js - 执行上下文和作用域以及闭包

首先&#xff0c;咱们通常被"执行上下文"&#xff0c;"执行上下文环境"&#xff0c;"上下文环境"&#xff0c;"执行上下文栈"这些名词搞混。那我们一一来揭秘这些名字的含义。 这一块一直比较晦涩难懂&#xff0c;还是需要仔细去斟酌斟…

Spring之JDBCTemplate

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 一、Spring对不同的持久化支持&#xff1a; Spring为各种支持的持久化技术&#xff0c;都提供了简单操作的模板和回调 ORM持久化技术模…

从蚂蚁金服实践入手,带你深入了解 Service Mesh

本文整理自蚂蚁金服高级技术专家敖小剑在 QCon 上海 2018 上的演讲。我是来自蚂蚁金服中间件团队的敖小剑&#xff0c;目前是蚂蚁金服 Service Mesh 项目的 PD。我同时也是 Servicemesher 中国技术社区的创始人&#xff0c;是 Service Mesh 技术在国内最早的布道师。我今天给大…

Android应用开发—FragmentManager如何管理fragments

本文主要摘录自Android中使用FragmentManager管理fragments 和 浅谈FragmentManager与fragment之一二事 先讲下自己对fragment的理解&#xff1a; 对于fragment&#xff0c;有太多官方文档和博文来介绍&#xff0c;此处不做转述&#xff1a;我感觉android提供fragment这种组件…

数组指针 和 指针数组

最近发现公司有些人说怎样区分 数组指针 和 指针数组 &#xff1f; 其实 很简单&#xff1b; 数组指针&#xff0c; 先是&#xff08;定语 &#xff09; &#xff08;主体&#xff09;&#xff0c; &#xff08;定语 数组&#xff09; &#xff08;主体 指针&#xff09…

在云服务器上注意GeoServer和ShadowDataMap的跨域设置

在云服务器上注意GeoServer和ShadowDataMap的跨域设置 1、对于支持cors的网络资源 可以在ShadowDataMap的devserverconfig.json里设置相应的跨域资源 提示&#xff1a;geoserver发布的地图服务虽然同在一个服务器上&#xff0c;但是端口不一样&#xff0c;同样需要设置跨域 如&…

Guava ImmutableCollection简介

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 ImmutableCollection代码定义 GwtCompatible(emulatedtrue) public abstract class ImmutableCollection<E> extends AbstractCo…