回调可能引发内存泄漏?代码泄漏排查与优化方案咨询
你的代码是否存在内存泄漏?怎么优化?
咱们一步一步拆解你的问题:
一、当前代码确实存在内存泄漏问题
你的代码里有两处明显的内存泄漏风险:
- 匿名内部类
Update listener导致的泄漏
匿名内部类默认会持有外部Activity的强引用,而你把这个listener传给了单例ServerManager(它的生命周期和应用一致)。当Activity被销毁(比如用户返回、屏幕旋转)时,ServerManager仍然持有listener的强引用,进而间接持有Activity的引用,导致Activity无法被GC回收,最终引发内存泄漏。 - 非静态内部类
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
相关产品推荐
相关产品推荐

