在 Android 开发中,动态注册广播(通过 registerReceiver())若处理不当容易引发内存泄漏。以下是预防内存泄漏的核心方案和代码示例:
1. 生命周期成对管理
确保在组件的生命周期中成对调用 registerReceiver() 和 unregisterReceiver()。
示例:在 Activity 中注册/注销
public class MainActivity extends AppCompatActivity {
private BroadcastReceiver mReceiver;
@Override
protected void onStart() {
super.onStart();
// 动态注册广播
mReceiver = new MyBroadcastReceiver();
IntentFilter filter = new IntentFilter("CUSTOM_ACTION");
registerReceiver(mReceiver, filter);
}
@Override
protected void onStop() {
super.onStop();
// 确保注销广播接收器
if (mReceiver != null) {
unregisterReceiver(mReceiver);
mReceiver = null;
}
}
}
- 关键点:
- 在
onStart()注册,在onStop()注销(或onResume()/onPause()成对使用)。 - 避免在
onDestroy()中注销,因为某些情况下可能无法保证执行(如系统回收资源时)。
- 在
2. 避免内部类隐式引用
匿名内部类或非静态内部类会隐式持有外部类(如 Activity)的引用,导致无法释放。
改进方案:使用静态内部类 + 弱引用
public class MainActivity extends AppCompatActivity {
private MyBroadcastReceiver mReceiver;
// 静态内部类,不持有外部类的隐式引用
private static class MyBroadcastReceiver extends BroadcastReceiver {
private WeakReference<MainActivity> mActivityRef;
MyBroadcastReceiver(MainActivity activity) {
mActivityRef = new WeakReference<>(activity);
}
@Override
public void onReceive(Context context, Intent intent) {
MainActivity activity = mActivityRef.get();
if (activity != null) {
// 处理广播逻辑
}
}
}
@Override
protected void onStart() {
super.onStart();
mReceiver = new MyBroadcastReceiver(this);
IntentFilter filter = new IntentFilter("CUSTOM_ACTION");
registerReceiver(mReceiver, filter);
}
@Override
protected void onStop() {
super.onStop();
if (mReceiver != null) {
unregisterReceiver(mReceiver);
mReceiver = null;
}
}
}
3. 避免在 Application 或长期存活组件中注册
在 Application 或长期存活的组件(如单例)中注册广播时,需手动管理生命周期,否则接收器会一直持有引用。
错误示例
public class MyApp extends Application {
private BroadcastReceiver mReceiver;
@Override
public void onCreate() {
super.onCreate();
// 错误:在 Application 中注册但未注销
mReceiver = new MyReceiver();
registerReceiver(mReceiver, new IntentFilter("CUSTOM_ACTION"));
}
}
改进方案
在合适的时机(如组件销毁时)主动调用 unregisterReceiver()。
4. 使用 LocalBroadcastManager(已过时,替代方案)
LocalBroadcastManager 已弃用,但其设计思想值得借鉴:使用应用内局域广播减少泄漏风险。替代方案为:
- 使用
LiveData或事件总线(如EventBus、RxJava)。 - 直接使用
Context注册,但严格控制生命周期。
5. 检测工具辅助
使用工具检测内存泄漏:
- LeakCanary:自动检测内存泄漏并生成报告。
- Android Profiler:手动分析内存使用情况。
总结
| 关键点 | 解决方案 |
|---|---|
| 生命周期管理 | 在 onStart()/onStop() 或 onResume()/onPause() 中成对注册/注销。 |
| 避免隐式引用 | 使用静态内部类 + 弱引用持有外部类。 |
| 避免长期持有 | 不在 Application 或单例中随意注册广播。 |
| 替代方案 | 使用 LiveData 或事件总线替代部分广播场景。 |
通过以上措施,可有效预防动态注册广播导致的内存泄漏问题。