前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >重谈Handler的内存泄漏

重谈Handler的内存泄漏

作者头像
Yif
发布2019-12-26 15:03:17
1.1K0
发布2019-12-26 15:03:17
举报
文章被收录于专栏:Android 进阶Android 进阶
undefined
undefined

Handler 的内存泄漏问题

在多线程操作中,handler会使用的非常多,但是每次使用handler你有没有考虑内存泄漏的问题。

如果你使用handler进行操作时,你会发现出现以下提示 This Handler class should be static or leaks might occur (anonymous android.os.Handler)这样的提示。翻译: 由于此Handler被声明为内部类,因此可能会阻止外部类被垃圾回收。 如果Handler使用LooperMessageQueue作为主线程以外的线程,则没有问题。 如果Handler正在使用主线程的Looper或MessageQueue,则需要修复Handler声明,如下所示:将Handler声明为静态类; 在外部类中,实例化外部类的WeakReference,并在实例化Handler时将此对象传递给Handler; 使用WeakReference对象对外部类的成员进行所有引用。

警告原因:handler没有设置为静态类,声明内部类可能会阻止被GC回收,从而导致内存泄漏

那么为什么会造成内存泄漏呢。 首先来说下什么是内存泄漏 内存泄漏(Memory Leak):指的是程序已经动态分配的堆内存由于某种原因程序未释放或者无法释放,造成系统资源浪费,会造成程序运行缓慢甚至系统崩溃等严重后果。 问题代码:

代码语言:javascript
复制
public class MainActivity extends AppCompatActivity {
    private Handler mHandler = new Handler();
    private TextView mTextView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = (TextView) findViewById(R.id.tv);
        //模拟内存泄漏
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                mTextView.setText("yiyi");
            }
        }, 1000);
    }
}

内存泄漏原因

从上面问题代码,可以看出这里通过内部类方式创建handler,而在java中,非静态内部类会持有外部类的引用,这里的postDelayed是一个延迟处理消息,将一个handler装入到message中,将消息放进消息队列messageQueueLooper进行取消息进行处理。如果此时activity要退出了,想要调用destroy销毁,但是此时Looper正在处理消息,Looper的生命周期明显比activity长,这将使得activity无法被GC回收,最终造成内存泄漏。并且此时handler还持有activity的引用,也是造成内存泄漏的一个原因(不是根本原因)。

但是我觉得真正handler造成内存泄漏的根本原因是生命周期比activity长,比如TextView也是内部类创建的,那么它怎么没有造成内存泄漏,它也持有外部类Activity的引用,根本原因是它的生命周期比Activity短,Activity销毁时候,它可以被GC回收

总结

handler有没有处理的消息或者正在处理消息,此时Handler的生命周期明显比Activity长,GC持有Activity与handler两者的引用,导致Activity无法被GC回收,造成内存泄漏。而handler是不是内部类,并不是造成内存泄漏的根本原因。

解决方案

静态内部类+弱引用

将Handler的子类设置成 静态内部类,并且可加上 使用WeakReference弱引用持有Activity实例 原因:弱引用的对象拥有短暂的生命周期。而垃圾回收器不管内存是否充足都会回收弱引用对象。

代码语言:javascript
复制
public class HandlerActivity extends AppCompatActivity  {
    private static class MyHandler extends Handler {
    private final WeakReference<HandlerActivity> mActivity;
    public MyHandler(HandlerActivity activity) {
        mActivity = new WeakReference<HandlerActivity>(activity);
    }
 
    @Override
    public void handleMessage(Message msg) {
        HandlerActivity activity = mActivity.get();
        if (activity != null) {
        }
    }
 
    private final MyHandler mHandler = new MyHandler(this);
    private static final Runnable mRunnable = new Runnable() {
        @Override
        public void run() { }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mHandler.postDelayed(mRunnable, 1000 * 60 * 1);
        finish();
    }
}

Activity生命周期结束时,清空消息队列

只需在ActivityonDestroy()方法中调用mHandler.removeCallbacksAndMessages(null);就行了。

代码语言:javascript
复制
@Override
protected void onDestroy() {
    super.onDestroy();
    if(handler!=null){
        handler.removeCallbacksAndMessages(null);
        handler = null;
    }
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年7月27日 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Handler 的内存泄漏问题
  • 内存泄漏原因
    • 总结
    • 解决方案
      • 静态内部类+弱引用
        • Activity生命周期结束时,清空消息队列
        相关产品与服务
        消息队列 CMQ 版
        消息队列 CMQ 版(TDMQ for CMQ,简称 TDMQ CMQ 版)是一款分布式高可用的消息队列服务,它能够提供可靠的,基于消息的异步通信机制,能够将分布式部署的不同应用(或同一应用的不同组件)中的信息传递,存储在可靠有效的 CMQ 队列中,防止消息丢失。TDMQ CMQ 版支持多进程同时读写,收发互不干扰,无需各应用或组件始终处于运行状态。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档