解决Handler导致的内存泄漏真实样例

背景

最近自己项目上用了网上的AutoScrollViewPager 开源Viewpager。没怎么关注别人开源的项目一些代码质量问题, 因为潜意识上别人开源在网上的肯定是令人满意的代码。最近意识到了这种心态其实并不好,而且不利于自身技术的提升。

样例
贴这个View的内存泄漏的样例,是因为发现很多程序员们在使用一些第三方开源框架,特别是一些自定义view的特效时,会用到一些延时任务之类的,那就会用到Handler这个类。在Android中,典型的Context+Handler造成的内存泄漏现象也是常见的。
来看下没有处理过之前得AutoScrollViewPager 中Handler的代码:
private class H extends Handler {
        @Override
        public void handleMessage(Message msg) {

            Context context = getContext();
            switch (msg.what) {
                case MSG_AUTO_SCROLL:
                    setCurrentItem(getCurrentItem() + 1);
                    sendEmptyMessageDelayed(MSG_AUTO_SCROLL, intervalInMillis);
                    break;
                default:
                    super.handleMessage(msg);
                    break;
            }
        }
    }

问题:当程序进入handlerMessage的时候,可能context所在的Activity,Fragment已经关闭,那么因为Handler的存在,因为Handler new出来后是和当前线程绑定在一起的, 不明白的同学可以去看看Handler,MessageQuee,Looper相关源码。所以Handler在执行handlerMessage里因为持有当前自定义view的context,导致context在Activity,Fragment关闭时候无法正常释放,造成context内存泄漏。
来看下Memory Usage在Activity关闭后给出的结果:
Objects:
Views: 16 ViewRootImpl: 1
AppContexts: 4 Activities: 1
Assets: 6 AssetManagers: 6
Local Binders: 15 Proxy Binders: 20
Parcel memory: 5 Parcel count: 23
Death Recipients: 1 OpenSSL Sockets: 0
可以看到Activity依然存活。
正确修改后:

private static class H extends Handler {
        private AutoScrollViewPager autoScrollViewPager;
        private WeakReference<AutoScrollViewPager> viewHolder;
        public H(AutoScrollViewPager autoScrollViewPager){
            this.autoScrollViewPager = autoScrollViewPager;
            viewHolder = new WeakReference<AutoScrollViewPager>(autoScrollViewPager);
        }

        @Override
        public void handleMessage(Message msg) {
            if (viewHolder.get()!=null){
                switch (msg.what) {
                    case MSG_AUTO_SCROLL:
                        autoScrollViewPager.setCurrentItem(autoScrollViewPager.getCurrentItem() + 1);
                        sendEmptyMessageDelayed(MSG_AUTO_SCROLL, autoScrollViewPager.intervalInMillis);
                        break;
                    default:
                        super.handleMessage(msg);
                        break;
                }
            }

        }
    }

这里做了几步:
1.将Handler声明为static
2.因为在handlerMessage中无法访问外部非静态方法,所以传入autoviewpager作为成员变量
3.使用WeakReference包裹autoviewpager(context) 使程序执行完handlerMessage之后的GC回收时回收autoviewpager中的context。
看现在的Memory Usage结果:
Objects
Views: 0 ViewRootImpl: 0
AppContexts: 3 Activities: 0
Assets: 6 AssetManagers: 6
Local Binders: 13 Proxy Binders: 19
Parcel memory: 5 Parcel count: 22
Death Recipients: 1 OpenSSL Sockets: 0
分享结束,告诫自己,使用handler注意内存泄漏问题,还Android一个绿色环境。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值