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

在Android中脱离Main Activity上下文执行后台BLE扫描

在Android Worker中实现不受Activity生命周期影响的周期性后台BLE扫描

1. 选对上下文:用ApplicationContext,别碰Activity上下文

Worker初始化时自带的上下文是ApplicationContext,这是全局的应用级上下文,完全不受Activity/Fragment等组件的生命周期影响,正好匹配你的需求。直接在Worker的doWork()方法里通过getApplicationContext()获取就行,绝对不要传递Activity的上下文进来——那会导致内存泄漏,还会跟着Activity销毁失效。

2. 蓝牙组件初始化的正确代码示例

在Worker里初始化蓝牙扫描相关组件的代码如下:

class BleScanWorker(
    context: Context,
    workerParams: WorkerParameters
) : Worker(context, workerParams) {

    override fun doWork(): Result {
        // 获取全局ApplicationContext
        val appContext = applicationContext

        // 初始化蓝牙管理器
        val bluetoothManager = appContext.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
        val bluetoothAdapter = bluetoothManager.adapter
        val bleScanner = bluetoothAdapter.bluetoothLeScanner

        // 检查蓝牙是否可用
        if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled) {
            // 处理蓝牙未开启的情况,比如返回失败或触发开启逻辑
            return Result.failure()
        }

        // 配置扫描参数和回调
        val scanSettings = ScanSettings.Builder()
            .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER) // 后台扫描用低功耗模式更合适
            .build()
        val scanCallback = object : ScanCallback() {
            override fun onScanResult(callbackType: Int, result: ScanResult?) {
                // 处理扫描到的设备
                result?.let {
                    // 你的业务逻辑
                }
            }

            override fun onScanFailed(errorCode: Int) {
                // 处理扫描失败
            }
        }

        // 开始扫描
        bleScanner.startScan(null, scanSettings, scanCallback)

        // Worker的doWork()是同步执行的,如需扫描一段时间后停止,添加延迟
        Thread.sleep(10000) // 扫描10秒后停止
        bleScanner.stopScan(scanCallback)

        // 返回成功,触发下一次周期性任务(若用了PeriodicWorkRequest)
        return Result.success()
    }
}

3. 实现周期性扫描的关键配置

要让Worker周期性执行,必须用PeriodicWorkRequest而非一次性的OneTimeWorkRequest,示例代码如下:

// 配置每15分钟执行一次(系统允许的最小周期为15分钟)
val periodicWorkRequest = PeriodicWorkRequestBuilder<BleScanWorker>(15, TimeUnit.MINUTES)
    .setConstraints(
        Constraints.Builder()
            .setRequiredNetworkType(NetworkType.NOT_REQUIRED) // BLE扫描不需要网络
            .setRequiresBle(true) // 要求蓝牙可用
            .build()
    )
    .build()

// 将任务提交给WorkManager
WorkManager.getInstance(appContext).enqueue(periodicWorkRequest)

4. 后台扫描的权限与系统限制注意事项

  • 权限配置:根据目标API级别,在Manifest中添加对应权限:
    • API 31+:BLUETOOTH_SCAN、BLUETOOTH_ADVERTISE、BLUETOOTH_CONNECT,后台扫描可能还需要ACCESS_FINE_LOCATION(部分设备要求)
    • API 23-30:ACCESS_FINE_LOCATION、BLUETOOTH、BLUETOOTH_ADMIN
  • Android 8.0+后台限制:后台扫描频率不能过高,系统会限制过于频繁的扫描;若应用被强制停止,WorkManager任务会暂停,如需更稳定的后台扫描,可结合android:foregroundServiceType="location"的前台服务实现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 08:12:20