1. 问题
先看以下代码:

第一种写法:

public class MainActivity extends AppCompatActivity {

...
...
...

private class MyHandler extends Handler {
@Override
public void handleMessage(@NonNull Message msg) {
if (msg.what == 10086) {
mTv.setText(String.valueOf(msg.arg1));
}
}
}

...
...
...

}
第二种写法:

public class MainActivity extends AppCompatActivity {

...
...
...

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};

...
...
...

}
}
?

对于 Handler?这两种创建方式,Android Studio 虽然不会报错,但是会有提醒:

意思是 Handler 类必须为静态,否则会造成泄漏。

2.原因
非静态内部类和匿名内部类会持有外部类的引用。在 Handler 消息队列还有正在处理或者未处理消息时候,消息队列中的 Message 持有 Handler 实例的引用。由于Handler 为非静态内部类或者匿名内部类时候,又持有外部类的引用,也就是持有外部 MainActivity 实例。而这样的引用关系会一直保持。

此时,如果销毁外部类(MainActivity 实例),由于存在引用关系,垃圾回收机制中,外部类(MainActivity 实例)就无法被回收,从而造成内存泄漏。

内存泄漏在 Android 开发是一个严重的问题,系统给每个应用分配的内存是固定的,一旦发生了内存泄漏,就会导致应用的可用内存越来越小,最终导致 OOM 的发生。

3.解决方法
方法1:静态内部类+弱引用

将 Handler 的子类设置成静态内部类,静态内部类不再默认持有外部类的引用,从而使得引用关系不再存在。同时,再加上使用弱引用(WeakReference)持有Activity实例,当发生GC时候,一旦发现了只具有弱引用的对象,不管当前内存是否足够,都会回收它的内存。

public class MainActivity extends AppCompatActivity {

...
...
...

private static class MyHandler extends Handler {
WeakReference<Activity> reference;

public MyHandler(Activity activity) {
reference = new WeakReference<>(activity);
}

@Override
public void handleMessage(@NonNull Message msg) {
if(null!=reference)
{
MainActivity activity = (MainActivity) reference.get();
if(null!=activity) {
if (msg.what == 10086) {
activity.mTv.setText(String.valueOf(msg.arg1));
}
}
}
}
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler=new MyHandler(this);
...
...
...

}
}
?2. 及时清除消息

当外部类(Activity)生命周期结束时候,清除 Handler 消息队列里的所有消息。

@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);

Android Handler 内存泄漏问题的更多相关文章

  1. Android Handler 内存泄漏,文末消息机制的小总结

    1. 内存泄漏的Activity public class MainActivity extends AppCompatActivity { private static final int MESS ...

  2. 利用Android Studio、MAT对Android进行内存泄漏检测

    利用Android Studio.MAT对Android进行内存泄漏检测 Android开发中难免会遇到各种内存泄漏,如果不及时发现处理,会导致出现内存越用越大,可能会因为内存泄漏导致出现各种奇怪的c ...

  3. Android防止内存泄漏以及MAT的使用

    Android发生内存泄漏最普遍的一种情况就是长期保持对Context,特别是Activity的引用,使得Activity无法被销毁.这也就意味着Activity中所有的成员变量也没办法销毁.本文仅介 ...

  4. android 常见内存泄漏原因及解决办法

    android常见内存泄漏主要有以下几类: 一.Handler 引起的内存泄漏. 在Android开发中,我们经常会使用Handler来控制主线程UI程序的界面变化,使用非常简单方便,但是稍不注意,很 ...

  5. android性能测试内存泄漏

    1.什么是内存泄漏?     适用于该系统的内存使用内存泄漏,未回复(释放),该内存可以没有事业,也不能被其他人使用使用自己. 2.出有什么差别?    内存泄漏是分配出去的内存无法回收.    内存 ...

  6. [原理] Android Native内存泄漏检测原理解析

    转载请注明出处:https://www.cnblogs.com/zzcperf/articles/11615655.html 上一篇文章列举了不同版本Android OS内存泄漏的检测操作(传送门), ...

  7. Android App 内存泄漏Handler

    Android App 内存泄露之Handler Handler也是造成内存泄露的一个重要的源头,主要Handler属于TLS(Thread Local Storage)变量,生命周期和Activit ...

  8. [轉]Android的内存泄漏和调试

    一. Android的内存机制 Android的程序由Java语言编写,所以Android的内存管理与Java的内存管理相似.程序员通过new为对象分配内存,所有对象在java堆内分配空间:然而对象的 ...

  9. Android 常见内存泄漏的解决方式

    在Android程序开发中.当一个对象已经不须要再使用了,本该被回收时.而另外一个正在使用的对象持有它的引用从而导致它不能被回收.这就导致本该被回收的对象不能被回收而停留在堆内存中,内存泄漏就产生了. ...

随机推荐

  1. mysql连接数据库时报2003错误怎么解决

    mysql 2003是连接错误,连不上服务器. 你目前可以如下方法:进入控制面板->服务管理(我的是管理工具),->服务,然后找到Mysql服务,右键修改属性,改为自启动,以后再重启就没有 ...

  2. createTextNode() 方法和createTextNode()方法

    <!DOCTYPE html><html><head><meta charset="utf-8"><title>菜鸟教程 ...

  3. Redis利用Pipeline加速查询速度的方法

    1. RTT Redis 是一种基于客户端-服务端模型以及请求/响应协议的TCP服务.这意味着通常情况下 Redis 客户端执行一条命令分为如下四个过程: 发送命令 命令排队 命令执行 返回结果 客户 ...

  4. Vue之动态class写法总结

    对象方法 最简单的绑定 :class="{ 'active': isActive }" 判断是否绑定一个active :class="{'active':isActive ...

  5. Linux Exploit系列之六 绕过ASLR - 第一部分

    绕过ASLR - 第一部分 什么是 ASLR? 地址空间布局随机化(ASLR)是随机化的利用缓解技术: 堆栈地址 堆地址 共享库地址 一旦上述地址被随机化,特别是当共享库地址被随机化时,我们采取的绕过 ...

  6. 让虚拟机中的MySQL可以被主机访问

    1.VirtualBox对Ubuntu系统进行设置,“网络”选择“桥接网卡” 2.安装MYSQL服务器 sudo su;   apt-get intall mysql-server 3.赋予远程访问的 ...

  7. 第十篇.3、ython并发编程之多线程理论部分

    一 什么是线程 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程 车间负责把资源整合 ...

  8. 基于nginx与Tomcat实现负载均衡

    server1:192.168.200.113(nginx服务端) server2:192.168.200.111(Tomcat服务端) server1中nginx的配置文件 nginx.conf h ...

  9. linux pip使用国内源

    最近在Linux里面使用pip安装应用的速度十分的慢,于是便上网找了一些国内的源. 清华大学:https://pypi.tuna.tsinghua.edu.cn/simple 阿里云:https:// ...

  10. PHP强制修改返回的状态码

    在最后的程序执行完毕之前,加入下列语句,即可实现所有的返回码都为200即使在服务器内部发生错误,会报500情况下只要加上register_shutdown_function函数的处理同样可以实现返回2 ...