一次dialog导致的内存泄漏

本文详细记录了一次由于Dialog动画导致的内存泄漏问题。在Activity退出时,由于Dialog的渐变动画,使得Dialog仍持有Activity引用,造成内存泄漏。通过分析发现,问题在于Handler.postDelayed()方法,在动画执行期间,Activity被finish(),导致内存泄漏。解决方案是延迟执行finish(),确保它在Dialog动画结束后执行。此外,文中还提到在某些情况下,重复创建Dialog可以避免内存泄漏问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一次Dialog导致的内存泄漏

今天上午10:30来到公司后,一头扎进了张鸿洋大神所写的OkHttpUtils源码中去,继续昨晚未完成的任务,11:30后,终于对整个框架有了一个比较全局、清晰的了解,心里更是对大神充满满满的崇拜和敬意;然后回到公司的工作,打开jira,发现距离我两个工位的美女测试姐姐给我提了一个页面刷新bug,卧槽,居然还有bug,赶紧拿起数据线,插上Mac电脑和华为荣耀6手机,进入bug页面,执行相关操作,程序按正常逻辑自动退出进入上一层页面,检查应该刷新的两个页面,发现通过EventBus通知刷新的页面都刷新了,没问题啊,嗯嗯…?好像刚才执行点击操作时,在页面退出之前,手机屏幕好像出现了短暂的黑屏现象,确认应该没看错,赶紧打开Android Studio的log日志,发现如下:

error_log

我靠,居然发生了内存泄漏,按照日志调用栈的信息,应该是Activity在退出finish后,Dialog仍然持有Activity的引用,从而导致内存泄漏。
但是我明明已经调用了dialog.dismiss()方法了,这个Dialog与Activity应该没有关联引用了,怎么仍然持有引用?
下面是执行点击操作,弹出Dialog的代码

final TitleContentDialog dialog = new TitleContentDialog(ReceivableMoneyRecordActivity.this);
                        dialog.setContentView(getContentViewForDialog("确认删除此回款记录?"));
                        dialog.setTitle(null);
                        dialog.setCancelButton("取消", new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                dialog.dismiss();
                            }
                        });
                        dialog.setConfirmButton("确定", new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                dialog.dismiss();
                                deleteRecord();
                            }
                        });
                        dialog.show();

可以看出点击确定后,dialog先是dismiss(),然后执行deleteRecord()方法,deleteRecord()里面执行请求网络的删除操作。

打开浏览器,输入问题,都说是Activity finish时,Dialog仍然可见,要在Activity的onDestroy()方法中,确保已经关闭了Dialog,
OK,那我就在onDestroy()方法里面校验Dialog,我把Dialog提取出方法,成为Activity的一个成员变量mDeleteDialog;
同时重写Activity的onDestroy()方法:


    @Override
    protected void onDestroy() {
        //防止内存泄漏
        if (mDeleteDialog.isShowing()) {
            mDeleteDialog.dismissImmediately();
        }
        mDeleteDialog = null;
   
`public static Dialog showDialog(Context context)` 这个方法是一个静态方法,它创建并显示一个Dialog。如果`context`对象在这次会话结束后没有得到适当的清理,就可能导致内存泄露。 为了防止Context内存泄露,你可以采取以下措施: 1. **及时关闭Dialog**:在不再需要Dialog时,记得通过`dialog.dismiss()`方法将其关闭。这将释放Dialog所占用的资源,包括关联的Context。 ```java Dialog dialog = showDialog(context); // 使用完dialog后 if (dialog != null) { dialog.dismiss(); } ``` 2. **避免静态引用**:如果`showDialog`方法返回的是一个静态引用,那么每次请求都会持有全局Context,直到Activity生命周期结束。尽量避免这种设计,可以考虑返回一个非静态Dialog对象,并由使用者负责管理其生命周期。 3. **使用WeakReference**:如果你无法控制Dialog的关闭时机,可以使用`WeakReference<Context>`来弱引用Context。当Context被垃圾回收时,这个引用也会失效,不会阻止Context被释放。 4. **确保Context持有者对象被正确销毁**:如果是某个持有Context的活动或服务导致内存泄露,确保该活动或服务在合适的时候被finish()或者手动unregister掉。 5. **使用ContextCompat**:在Android API 26及以上版本,可以使用`ContextCompat`提供的`getApplicationContext()`替代直接传递Context,这样可以在某些场景下自动管理Context的生命周期。 记得始终关注泄漏检测工具如LeakCanary、Honeycomb等,以便在实际项目中发现并修复潜在的问题。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值