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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:51:00