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. PHP 下载mysql数据到PHPExcel表格

    第一步:先到官网(https://github.com/PHPOffice/PHPExcel)下载PHPExcel 第二步:放到第三方库 第三步: /** * 封装:信息导出 * @param $da ...

  2. Seeker:一款可获取高精度地理和设备信息的工具分析

    Seeker是一款可以获取高精度地理和设备信息的工具.其利用HTML5,Javascript,JQuery和PHP来抓取设备信息,以及Geolocation接口实现对设备高精度地理位置的获取. See ...

  3. linux使用VNC服务轻松远程安装oracle

    VNC服务在远程服务器上安装oracle,新手安装oracle时总会遇到这样或者那样的问题,下面我就详细解说一下安装过程,其实oracle安装很简单,并不要把他相像的特别复杂. 本环境用:centos ...

  4. Golang 方法接收者是值还是指针问题

    对于普通结构体作为接收者,值和指针并没有区别. (以下代码摘抄自Go In Action 中文版) type defaultMatcher struct{} // 方法声明为使用 defaultMat ...

  5. 格式化json扩展

    json-handle 直接在chrome应用商店搜索JSON-handle或者去github搜索可用插件即可

  6. 白盒测试之JUnit与SpringTest的完美结合

    通过白盒的单元测试可以验证程序基本功能的有效性,从而保证整个系统的质量,功在一时,利在千秋.目前80%以上公司后台还是基于java,尤其是后台大量采用Spring框架,我们这里采用Junit和Spri ...

  7. 【LeetCode】451-根据字符出现频率排序

    题目描述 给定一个字符串,请将字符串里的字符按照出现的频率降序排列. 示例 1: 输入: "tree" 输出: "eert" 解释: 'e'出现两次,'r'和' ...

  8. 高性能mysql 第4章 Schema与数据类型优化

    基本原则: 更小的通常更好:占用更少的磁盘 内存和cpu缓存.如varchar(2)和varchar(100). 简单就好:比如整形比字符型代价更低.使用日期型来存储日期而不是字符串.使用整形存储ip ...

  9. [LeetCode 92] Reverse Linked List II 翻转单链表II

    对于链表的问题,根据以往的经验一般都是要建一个dummy node,连上原链表的头结点,这样的话就算头结点变动了,我们还可以通过dummy->next来获得新链表的头结点.这道题的要求是只通过一 ...

  10. linux学习:【第3篇】之常见命令2

    一.知识点回顾 临时:关闭当前正在运行的 /etc/init.d/iptables stop 永久:关闭开机自启动 chkonfig iptables off ll /var/log/secure # ...