Activity中unregisterReceiver的调用位置及广播接收器泄漏问题排查
解决Activity中BroadcastReceiver泄漏问题:正确调用unregisterReceiver的时机
这个广播泄漏的坑我之前踩过好几次!先给你拆解下错误原因:Activity has leaked IntentReceiver 本质是你的Receiver还和Activity绑定着,但Activity已经被系统回收或者处于不可用状态,而你没有在合适的时机注销它。你现在只在跳转到其他Activity前注销,这种方式覆盖不了所有场景,比如系统因内存不足回收Activity时,你的注销代码根本没机会执行,自然就会泄漏。
最稳妥的做法:绑定Activity生命周期
根据你的广播使用场景,选择对应的生命周期配对:
1. 全局接收(只要Activity存在就接收)
如果广播需要在Activity整个生命周期内接收,就把注册放在onCreate(),注销放在onDestroy():
private BroadcastReceiver myReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化接收器和IntentFilter myReceiver = new MyBroadcastReceiver(); IntentFilter filter = new IntentFilter("com.example.MY_ACTION"); // 注册 registerReceiver(myReceiver, filter); } @Override protected void onDestroy() { super.onDestroy(); // 注销前先判空,避免未注册就注销抛出异常 if (myReceiver != null) { unregisterReceiver(myReceiver); myReceiver = null; // 置空切断引用,彻底避免泄漏 } }
2. 前台接收(仅Activity在前台时接收)
如果只需要Activity在前台可见时接收广播,就用onResume()注册,onPause()注销:
@Override protected void onResume() { super.onResume(); // 注册接收器 registerReceiver(myReceiver, filter); } @Override protected void onPause() { super.onPause(); if (myReceiver != null) { unregisterReceiver(myReceiver); } }
这种方式能避免Activity后台时还持有Receiver引用,也能在你跳转到其他Activity时自动注销(因为跳转时当前Activity会执行onPause())。
针对你场景的具体修复建议
你提到是在子类BLERunnable里注册的Receiver,还要注意这几点:
- 不要依赖子类的局部逻辑注销:比如你只在跳转前调用子类的注销方法,万一子类逻辑没被触发(比如Activity被系统回收),Receiver就会泄漏。必须在Activity的生命周期方法里兜底注销这个Receiver。
- 管理Receiver实例:如果每次初始化子类都会新建Receiver实例,要确保旧的实例已经被注销,或者用单例模式管理Receiver,避免多个实例同时注册。
- 加注册状态标记:可以在Activity里加个
boolean isReceiverRegistered的标记,注册时设为true,注销时设为false,每次注册前检查状态,避免重复注册,注销前也检查,避免未注册就注销的异常。
举个例子,针对你的BLERunnable里的Receiver:
// Activity里的代码 private BLERunnable bleRunnable; private BroadcastReceiver bleReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); bleRunnable = new BLERunnable(); bleReceiver = bleRunnable.getReceiver(); // 从子类获取Receiver实例 } @Override protected void onDestroy() { super.onDestroy(); // 兜底注销子类里的Receiver if (bleReceiver != null) { try { unregisterReceiver(bleReceiver); } catch (IllegalArgumentException e) { // 捕获未注册就注销的异常,避免崩溃 e.printStackTrace(); } bleReceiver = null; } }
这样不管子类的注销逻辑有没有执行,Activity销毁时都会兜底处理,彻底避免泄漏问题。
内容的提问来源于stack exchange,提问作者luckyging3r
相关产品推荐
相关产品推荐

