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

为何单次锁屏操作后BroadcastReceiver多次接收SCREEN_OFF Intent?

解决Android Service中SCREEN_ON/OFF广播多次接收的问题

你遇到的核心问题是BroadcastReceiver被重复注册——哪怕你认为只调用了一次onStartCommand(),但该方法实际可能被系统或业务代码多次触发(比如Service被系统重启、多次调用startService()),每次触发都会新增一个接收器实例。当锁屏/亮屏广播发送时,所有已注册的接收器都会响应,最终出现多次日志输出。

根治方案:

1. 增加注册状态标记,避免重复注册

在Service类中添加布尔变量标记注册状态,确保接收器仅被注册一次:

public class YourService extends Service {
    private boolean isReceiverRegistered = false;
    private EventsReceiver mScreenReceiver;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 仅当未注册时执行注册操作
        if (!isReceiverRegistered) {
            mScreenReceiver = new EventsReceiver();
            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_SCREEN_ON);
            filter.addAction(Intent.ACTION_SCREEN_OFF);
            registerReceiver(mScreenReceiver, filter);
            isReceiverRegistered = true;
        }
        // 根据业务需求返回启动模式,比如START_STICKY
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // 注销时校验状态,避免空指针或重复注销
        if (isReceiverRegistered && mScreenReceiver != null) {
            unregisterReceiver(mScreenReceiver);
            isReceiverRegistered = false;
            mScreenReceiver = null;
        }
    }

    // 自定义BroadcastReceiver实现
    private class EventsReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (Intent.ACTION_SCREEN_ON.equals(action)) {
                Log.d("InternetConnectionCheck", "ACTION_SCREEN_ON is received");
                Log.i("InternetConnectionCheck", "EventsReceiver.onReceive() " + action);
            } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
                // 处理锁屏逻辑
            }
        }
    }
}

2. 检查Service启动逻辑

确认代码中是否存在多次调用startService()的情况,若为绑定+启动的混合场景,需避免重复触发onStartCommand()。如果无需多次启动Service,可考虑用bindService()替代重复调用startService()。

3. 补充异常场景下的注销逻辑

Service的onDestroy()不一定会被系统调用(比如内存不足时被直接杀掉),可在onTaskRemoved()中也添加注销逻辑,进一步兜底:

@Override
public void onTaskRemoved(Intent rootIntent) {
    super.onTaskRemoved(rootIntent);
    if (isReceiverRegistered && mScreenReceiver != null) {
        unregisterReceiver(mScreenReceiver);
        isReceiverRegistered = false;
        mScreenReceiver = null;
    }
    stopSelf();
}

通过以上调整,就能彻底解决重复注册导致的广播多次接收问题,无需再依赖计数器的临时方案。

内容的提问来源于stack exchange,提问作者AmenAllah HAMDI

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 11:40:24