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

Android应用后台/被杀死时BeaconManagerListener停止运行如何解决

问题原因及修复方案

现有代码核心问题

  • BeaconManagerListener被声明为TimerTask内部的局部变量,没有全局持有引用,当应用退到后台后,该实例很容易被系统GC回收,导致回调无法触发
  • 重复注册Listener:每隔2秒重复执行setBeaconManagerListener替换原有监听,属于完全不必要的逻辑,反而会导致回调断连
  • 服务重启策略错误:onStartCommand返回START_NOT_STICKY,当服务被系统资源回收后不会自动重启,无法保持后台持续运行
  • 缺少后台运行必要权限:Android 10及以上版本需要后台位置权限才能在后台扫描蓝牙Beacon,Android 12及以上还需要专门的蓝牙扫描权限
  • 未处理厂商系统限制:国内主流厂商(华为、小米、OPPO、VIVO等)的系统默认会限制后台应用的蓝牙扫描行为,未加入电池优化白名单的应用退后台后扫描功能会被系统拦截

具体修复步骤

  1. 调整Listener的持有逻辑
    将BeaconManagerListener和Timer都改为Service的全局成员变量,避免被GC回收,同时移除TimerTask内部重复注册Listener的逻辑,仅在服务启动时注册一次监听。
  2. 修改服务重启策略
    将onStartCommand的返回值改为START_STICKY,服务被系统杀死后会自动重启,保持检测能力。
  3. 补全所需权限
    在AndroidManifest.xml中添加以下权限:
<!-- 基础蓝牙权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<!-- Android 12+ 蓝牙扫描权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- 位置权限,Beacon扫描必需 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- Android 10+ 后台位置权限 -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

同时要在应用启动时主动请求用户授权上述所有权限,缺少任意权限都会导致后台扫描失效。
4. 引导用户关闭电池优化
应用首次启动时引导用户将应用加入系统电池优化白名单,避免厂商系统拦截后台扫描行为。

修正后的核心Service代码示例

public class MyService extends Service {
    public static final String CHANNEL_ID = "ForegroundServiceChannel";
    int service_timer=0;
    Timer timer = new Timer();
    SensoroManager sensoroManager;
    // 全局持有Listener引用,避免GC回收
    BeaconManagerListener beaconManagerListener;

    @Override
    public void onCreate() {
        super.onCreate();
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        sensoroManager = SensoroManager.getInstance(MyService.this);
        String input = intent.getStringExtra("inputExtra");
        System.out.println("Sensoro 2" );
        createNotificationChannel();
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,
                0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("Foreground Service")
                .setContentText(input)
                .setSmallIcon(R.drawable.ic_launcher_background)
                .setContentIntent(pendingIntent)
                .build();
        startForeground(1,notification);

        // 初始化Listener,仅注册一次
        initBeaconListener();

        if (sensoroManager.isBluetoothEnabled()) {
            sensoroManager.setCloudServiceEnable(true);
            try {
                sensoroManager.startService();
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            Toast.makeText(MyService.this,"Bluetooth off",Toast.LENGTH_LONG).show();
        }

        // 仅保留日志打印逻辑,移除重复注册Listener的代码
        new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println("Sensoro 2" );
                service_timer++;
            }
        }, 0, 2000);

        // 修改为START_STICKY,服务被杀后自动重启
        return START_STICKY;
    }

    private void initBeaconListener() {
        beaconManagerListener = new BeaconManagerListener() {
            @Override
            public void onUpdateBeacon(ArrayList<Beacon> beacons) {
                for (Beacon beacon : beacons) {
                    System.out.println("Sensoro 3" );
                }
            }
            @Override
            public void onNewBeacon(Beacon beacon) {
                if (beacon.getSerialNumber().equals("0117C59B243C")){
                    System.out.println("Sensoro 3" );
                    System.out.println("Sensoro acc" +beacon.getAccuracy());
                }
            }
            @Override
            public void onGoneBeacon(Beacon beacon) {
                if (beacon.getSerialNumber().equals("0117C59B243C")){
                    System.out.println("Sensoro acc gone");
                    System.out.println("Sensoro acc Timer" +service_timer);
                }
            }
        };
        sensoroManager.setBeaconManagerListener(beaconManagerListener);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // 服务销毁时解绑Listener,避免内存泄漏
        if (sensoroManager != null) {
            sensoroManager.setBeaconManagerListener(null);
        }
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel serviceChannel = new NotificationChannel(
                    CHANNEL_ID,
                    "Foreground Service Channel",
                    NotificationManager.IMPORTANCE_DEFAULT
            );
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(serviceChannel);
        }
    }
}

内容的提问来源于stack exchange,提问作者Saleh Refaai

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 05:15:02