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

Android 7.0下BLE后台服务仅运行一次问题排查求助

分析你的BLE服务打包后仅运行一次的问题

我来帮你拆解这个问题,结合你的代码和Android 7.0(API 24)的系统特性,核心问题大概率出在这几个方面:

1. 服务启动模式的返回值不对

你在onStartCommand里直接返回了super.onStartCommand(...),默认返回值不会让系统在服务被回收后自动重启它。调试模式下系统对应用的限制更少,所以能维持3小时,但打包后系统一旦回收服务,就不会再重启,导致只运行一次。

修复建议:
把返回值改成START_STICKY或者START_REDELIVER_INTENT,根据你的需求选:

// 系统回收后内存充足时自动重启服务,适合周期性任务
return START_STICKY;
// 或者需要恢复最后一次任务时用这个
// return START_REDELIVER_INTENT;

2. Android 7.0的Doze模式限制了定时任务

Android 7.0引入的Doze模式会暂停后台应用的Timer、Handler这类定时任务来省电,而调试模式下系统会豁免你的应用,所以调试时能正常运行。打包后应用进入后台,定时任务被系统暂停,服务就停了。

修复建议:
替换Timer为符合省电机制的AlarmManager或者JobScheduler,比如用AlarmManager实现周期性任务:

AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, BleScanReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

long interval = 1000 * nSecondi;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    // 即使在Doze模式下也能触发的精确定时
    alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + interval, pendingIntent);
} else {
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 10000, interval, pendingIntent);
}

然后写一个广播接收器BleScanReceiver,在onReceive里触发BLE扫描和读取逻辑。

3. 代码混淆导致BLE回调失效

打包APK时如果开启了混淆,你的GattClientCallback可能被混淆重命名,系统无法正确调用回调方法,导致读取流程中断,服务看起来像是停止运行了。

修复建议:
在proguard-rules.pro里添加BLE相关类的混淆豁免:

// 保留你的Gatt回调类和方法
-keep class com.yourpackage.BlePowerService$GattClientCallback { *; }
// 保留系统BLE回调类
-keep class android.bluetooth.BluetoothGattCallback { *; }
-keepattributes *Annotation*,EnclosingMethod,Signature

记得把com.yourpackage换成你实际的包名。

4. 权限检查缺失

调试时Android Studio可能自动给了位置权限,但打包安装后用户可能没授予ACCESS_COARSE_LOCATION(Android 7.0扫描BLE必须的权限),导致扫描失败,服务找不到设备就停了。

修复建议:
在onStartCommand开头加权限检查:

if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
    return START_STICKY;
}

同时确保AndroidManifest.xml里声明了必要权限:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />

5. BLE连接和读取逻辑的阻塞问题

你代码里while(isReading)用Thread.sleep(1)轮询的方式会阻塞线程,很容易触发ANR,导致系统直接杀死服务。而且mGatt实例没有正确管理,连接丢失后没关闭旧实例,可能导致资源泄漏,后续无法重新连接。

修复建议:

  • 用回调驱动读取逻辑,在GattClientCallback的onCharacteristicRead回调里触发下一个特征的读取,避免阻塞线程:
// 启动读取队列
private void startReadingQueue() {
    if (ReadQueue != null && !ReadQueue.isEmpty()) {
        readNextChar(0);
    }
}

private void readNextChar(int index) {
    if (index >= ReadQueue.size()) {
        // 读取完成,标记结束
        continuaLetturaForza = false;
        continuaLetturaTemperatura = false;
        return;
    }
    BluetoothGattCharacteristic chara = ReadQueue.get(index);
    if (mGatt != null && mGatt.readCharacteristic(chara)) {
        // 等待onCharacteristicRead回调再读下一个
    } else {
        readNextChar(index + 1);
    }
}

// 在GattClientCallback里添加:
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
    super.onCharacteristicRead(gatt, characteristic, status);
    // 处理读取到的数据...
    // 读下一个
    readNextChar(ReadQueue.indexOf(characteristic) + 1);
}
  • 断开连接时记得调用mGatt.close()释放资源,并把mGatt置为null。

额外优化:改用前台服务

Android 7.0及以上后台服务更容易被回收,把服务设为前台服务能大幅降低被杀死的概率:

// 在onCreate或onStartCommand里启动前台服务
Notification notification = new NotificationCompat.Builder(this, "BLE_CHANNEL_ID")
        .setContentTitle("BLE数据采集")
        .setContentText("正在后台同步设备数据")
        .setSmallIcon(R.drawable.ic_ble_notification)
        .build();
startForeground(1, notification);

Android 9.0及以上需要在Manifest里加前台服务权限:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:48:29