You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

回调可能引发内存泄漏?代码泄漏排查与优化方案咨询

你的代码是否存在内存泄漏?怎么优化?

咱们一步一步拆解你的问题:

一、当前代码确实存在内存泄漏问题

你的代码里有两处明显的内存泄漏风险:

  1. 匿名内部类Update listener导致的泄漏
    匿名内部类默认会持有外部Activity的强引用,而你把这个listener传给了单例ServerManager(它的生命周期和应用一致)。当Activity被销毁(比如用户返回、屏幕旋转)时,ServerManager仍然持有listener的强引用,进而间接持有Activity的引用,导致Activity无法被GC回收,最终引发内存泄漏。
  2. 非静态内部类MyHandler导致的泄漏
    同样,非静态内部类MyHandler也持有Activity的强引用,如果Handler的消息队列里还有未处理的消息(比如sendEmptyMessage(100)还没被执行),这些消息会持有Handler的引用,进而锁住Activity,导致泄漏。

二、回调是否会持有Fragment引用?

答案是肯定的。如果是在Fragment里用匿名内部类实现的回调,这个回调同样会持有Fragment的强引用。要是这个回调被单例、全局对象这类长生命周期的实例持有,当Fragment销毁后,引用链无法断开,Fragment就会无法被GC回收,产生内存泄漏。

三、优化方案

针对这些问题,我们可以从切断强引用链、使用生命周期感知的方式来优化:

1. 将内部类改为静态内部类+弱引用

把Update的实现和MyHandler都改成静态内部类,并用WeakReference来持有Activity/Fragment的引用,这样不会阻止GC回收目标组件:

public class YourActivity extends AppCompatActivity {
    TextView textView;
    MyHandler h;
    StaticUpdateListener listener;

    interface Update {
        void update(Data data);
    }

    // 静态内部类+弱引用持有Activity
    private static class StaticUpdateListener implements Update {
        private final WeakReference<YourActivity> activityRef;

        public StaticUpdateListener(YourActivity activity) {
            this.activityRef = new WeakReference<>(activity);
        }

        @Override
        public void update(Data data) {
            YourActivity activity = activityRef.get();
            // 先判断Activity是否存活
            if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) {
                activity.textView.setText(data.getText());
                activity.h.sendEmptyMessage(100);
            }
        }
    }

    // 静态Handler+弱引用
    private static class MyHandler extends Handler {
        private final WeakReference<YourActivity> activityRef;

        public MyHandler(YourActivity activity) {
            this.activityRef = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            YourActivity activity = activityRef.get();
            if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) {
                switch (msg.what) {
                    case 100:
                        activity.textView.setText("бла бла");
                        return;
                }
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.your_layout);
        textView = findViewById(R.id.textView);
        h = new MyHandler(this);
        listener = new StaticUpdateListener(this);
        ServerManager.getInstance().addCallBack(listener);
    }
}

2. 在组件销毁时移除回调和Handler消息

在Activity的onDestroy方法里,主动切断ServerManager和回调的关联,同时清空Handler的消息队列:

@Override
protected void onDestroy() {
    super.onDestroy();
    // 从ServerManager移除回调,切断强引用链
    ServerManager.getInstance().removeCallback(listener);
    // 清空Handler所有未处理的消息和回调
    h.removeCallbacksAndMessages(null);
}

如果是Fragment,可以在onDestroy或者onDestroyView里做同样的操作。

3. 可选:使用生命周期感知组件

如果你的项目用了Jetpack,可以考虑用LiveData替代自定义回调,它会自动感知组件的生命周期,当组件销毁时自动取消订阅,从根源避免内存泄漏;或者用RxJava的Disposable,在组件销毁时手动 dispose 订阅。


内容的提问来源于stack exchange,提问作者Oleg May

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:13:00