在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
- API 31+:
- Android 8.0+后台限制:后台扫描频率不能过高,系统会限制过于频繁的扫描;若应用被强制停止,WorkManager任务会暂停,如需更稳定的后台扫描,可结合
android:foregroundServiceType="location"的前台服务实现。
内容的提问来源于stack exchange,提问作者gpeck
相关产品推荐
相关产品推荐

