关于handler内存泄露的问题

Android内存泄露问题:解决Handler引起的内存泄露 在Android中,当一个对象持有对其他对象的引用,并且这些引用没有被正确释放,就会导致内存泄露问题的发生。其中一个常见的内存泄露源是Handler,本文将介绍如何解决由Handler引起的内存泄露问题,并提供相应的源代码示例。在Android开发中,我们应该始终注意在适当的时候移除未处理的消息,以确保对象能够被正确释放,从而避免潜在的内存泄露问题。然而,由于Handler持有对Activity的引用,当Activity被销毁时,Handler可能仍然存在于消息队列中,这就导致了内存泄露。 阅读详情

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

public class SampleActivity extends Activity {

  private final Handler mLeakyHandler = new Handler() {
    @Override
    public 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();    
           }
     }
}

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

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

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

public class SampleActivity extends Activity {

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

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Post a message and delay its execution for 10 minutes.
    mLeakyHandler.postDelayed(new Runnable() {
      @Override
      public 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);
    }

    @Override
    public 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() {
      @Override
      public void run() { }
  };

  @Override
  protected 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。

WhatsApp网页版扫码分析 扫码登录本质上是WhatsApp的多设备登录,设备之间可以独立运行,那么当我们首次通过WhatsApp扫码登录二维码时,到底发生了那些事情?交换了那些数据? 阅读详情

相关推荐

MAX31855电路和程序,实现SPI和软件模拟时序两种方式读取数据

1. 概述 MAX31855为热电偶至数字输出转换器,内置14位模/数转换器(ADC)。器件带有冷端补偿检测和修正、数字控制器、SPI兼容接口,以及相关的控制逻辑,在温度控制器、过程控制或监测系统中设计用于配合外部微控制器(μC)工作。提供多个版本的器件,每个版本针对特定的热电偶类型(K、J、N、T或E型)进行优化和调整。热电偶类型以器件型号后缀表示(例如MAX31855K)。 器件输出14位...

睿思派克 1万+

Android报警告:this handler class should be static...

this handler class should be static…

pvting的博客 2612

告别手动操作!用Python脚本批量处理Siemens NX零件文件(导入/导出/移除参数)

本文详细介绍了如何利用Python脚本实现Siemens NX零件文件的批量处理,包括导入、导出和移除参数等操作。通过NX Open API和Python UF接口,工业设计师可以大幅提升工作效率,告别繁琐的手动操作。文章提供了完整的实战指南,涵盖环境配置、核心功能实现以及性能优化技巧,特别适合需要进行Siemens-NXUG二次开发的工程师参考。

weixin_28222493的博客 261

Handler当做内部类,导致内存泄露的问题

按照以前的handler的写法 ,现在的android studio总是会提示说什么内存泄露 。于是上网,stackoverflow上面真的能解决很多问题啊,比国内的论坛真的是水平不知道高到哪里去了。 这里转载一篇国外的这个问题的分析文章。并作出翻译。 首先给出网址链接: http://www.androiddesignpatterns.com/2013/01/inner-class-hand

安东尼的博客 2392

边缘设备选型指南:从数据采集到AI推理,工业物联网硬件如何匹配你的需求?

本文提供了一份全面的工业物联网边缘设备选型指南,系统性地阐述了如何根据数据采集、协议兼容性、边缘AI推理算力及环境适应性等核心需求匹配硬件。文章深入剖析了从CPU/GPU/NPU选择到MQTT、Sparkplug B等工业协议支持的实战考量,并强调了软件生态与全生命周期成本的重要性,旨在帮助项目负责人在复杂场景中做出明智决策。

weixin_29168813的博客 88

三极管和MOS管工作原理详解

PN结的形成 PN结是三极管以及场效应管中最基本的组成部分,要想彻底搞明白三极管以及场效应管的工作原理,必须先搞清楚PN结形成的原理和工作特性。 本征半导体以及空穴对 本征半导体(intrinsic semiconductor))完全不含杂质且无晶格缺陷的纯净半导体称为本征半导体。主要常见代表有硅、锗这两种元素的单晶体结构。硅、锗都是4价原子,在半导体内部形成相对稳定的共价键结构,如图 1所

技术交流是便宜的的博客 10万+

重谈Handler的内存泄漏

在多线程操作中,handler会使用的非常多,但是每次使用handler你有没有考虑内存泄漏的问题。 如果你使用handler进行操作时,你会发现出现以下提示 This Handler class should be static or leaks might occur (anonymous android.os.Handler)这样的提示。翻译: 由于此Handler被声明为内部类,因此可能会阻止外部类被垃圾回收。 如果Handler使用Looper或MessageQueue作为主线程以外的线程,则没

大模型训练 1052

Android 13 内置xapk安装包的方法

安装xapk 内置xapk

安卓兼职framework和app工程师的博客 224

This Handler class should be static or leaks might occur Android

首先解释下这句话This Handler class should be static or leaks might occur,大致意思就是说:Handler类应该定义成静态类,否则可能导致内存泄露。 具体如何解决,在国外有人提出,如下: Issue: Ensures that Handler classes do not hold on to a reference to an out...

weixin_30905133的博客 393

TMF8801 ToF激光测距传感器原理图设计,已量产(距离传感器)

这张 TMF8801 小板的外围结构就很有代表性。核心传感器是 U1 TMF8801,但真正构成量产价值的是外围那一圈:U2 把 VCC 整理成 3V,R1/R2/R5 与 R3/R4/R6 两组 10K 电阻稳定默认态,Q2 2N7002 和 U3 SN74LVC2G07DCKR 处理控制链路,传感器边上还有 C1/C4/C5 三颗 100nF 紧贴去耦。

不脱发的程序猿 159

基于STM32姿态解算-正点原子ATK-IMU901模块标准库开发——正点原子串口角度传感器模块十轴IMU加速度气压计陀螺仪_资料编号29

购买了正点原子的ATK-IMU901模块后,发现例程给的是HAL库的,本项目将HAL库例程转换为库函数版本(基于STM32)。实战开发,亲测无误。

嵌入式阿齐Archie 3864

This Handler class should be static or leaks might occur 解决办法

平时我们习惯直接在 activity 中 new handler() 或 extends handler 使用,而 "This Handler class should be static or leaks might occur" 属于一种提示信息,平时我们都可能不太关注(本人也是,但是最近面试中被问到,所以才来了解一下)。 首先解释下这句话This Handler

wpandroid 1135

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Handler引起的内存泄露问题

如果你在Activity中定义了一个内部Handler类,如下代码: public class MainActivity extends Activity { private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) {

itccccc的专栏 540

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

记录:关于匿名Handler内存泄露问题

记录贴,关于匿名Handler内存泄露问题

q1435076663的专栏 570

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

android 使用handler内存泄露问题

android中使用handler时容易出现内存泄露,如下

跪键盘的小泰迪 659

Handler声明成内部类所引起的内存泄露问题

首先Handler声明成内部类所引起内存泄露的原因:java机制的非静态内部类持有外部类的引用,导致外部Activity无法释放 常用的一个解决方案:将Handler声明成static的,并在Handler中增加对Activity的弱引用 注:什么是弱引用? WeakReference弱引用,与强引用(即我们常说的引用)相对,它的特点是,GC在回收时会忽略掉弱引用,即就算有弱引用指向某对象,

yjc_0314的博客 442

Handler导致的内存泄露问题

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

huanongjingchao的专栏 1391

android handler的内存泄露问题

转载:http://www.linuxidc.com/Linux/2013-12/94065.htm 什么是内存泄露? Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收。也就是说,一个对象不被任何引用所指向,则该对象会在被GC发现的时候被回收;另外,如果一组对象中只包含互相的引用,而没有来自它

important0534的专栏 311

Android中Handler使用不当导致内存泄露的问题

Android中Handler为什么使用不当会导致内存泄露问题 在使用Handler时,通常是new一个内部类(或匿名内部类): private Handler mHandler=new Handler(){ public void handleMessage(android.os.Message msg) { //Update UI... }; }; 当使...

JiYaRuo的博客 384

[Android 笔记十一] Handler内存泄露问题的分析及解决方法

来源:https://blog.youkuaiyun.com/l707941510/article/details/80641444 上一文章: 由于Android采取了单线程UI模型,开发者无法在子线程中更新UI,为此Android为我们提供了Handler这个工具,帮助开发者切换到主线程更新UI。在我们开发Android应用程序进行异步操作时,我们经常会使用到Handler类。通常会写出如下代码 private Handler mHandler = new Handler(){ @Override ..

weixin_38423311的博客 238

android内存泄漏导致的问题,解决Android使用Handler造成内存泄露问题

一、什么是内存泄露?Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收。也就是说,一个对象不被任何引用所指向,则该对象会在被GC发现的时候被回收;另外,如果一组对象中只包含互相的引用,而没有来自它们外部的引用(例如有两个对象A和B互相持有引用,但没有任何外部对象持有指向A或B的引用),这仍然属于不可到达...

weixin_35599418的博客 377

Android中使用中Handler的内存泄露问题

什么是内存泄露? Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收。也就是说,一个对象不被任何引用所指向,则该对象会在被GC发现的时候被回收;另外,如果一组对象中只包含互相的引用,而没有来自它们外部的引用(例如有两个对象A和B互相持有引用,但没有任何外部对象持有指向A或B的引用),这仍然属于不可到达

dyt的博客 398

Handler作为Activity的内部类所引起的内存泄露问题

前天参加某公司的面试,被问到一个关于Handler作为Activity的内部类所引起的内存泄露的问题。虽然当时答上来了,但是还是想在这里记录一下。 问题总共分为两问:         1、Handler作为Activity的内部类来使用,会导致什么问题。         第一问很容易答上来,非静态的内部类会持有外部类实例的引用。因此,当通过Handler.post(Runnable r)或者

Jason__Young的博客 747

Android开发中使用Handler类造成的内存泄露问题

Android开发中使用Handler类造成的内存泄露问题

itccccc的专栏 656
上一篇: 关于Android在线支付Alipay(支付宝)开发的经验分享
下一篇: 关于TabLayout+ViewPager组合实现多页面滑动
ht_android
博客等级 码龄12年 33粉丝 19原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值