use*_*988 1 android background bluetooth bluetooth-lowenergy android-workmanager
由于最近对后台服务和隐式广播的限制,Android开发人员只能使用JobScheduler以及更高级别的WorkManager来安排后台任务。
WorkManager的Worker类非常简单,但是我对实现正在进行的工作而不是一次性工作的最佳方法有些困惑。在我们的示例中,让我们考虑蓝牙低功耗扫描,但是同样的顾虑也适用于所有正在进行的不确定的工作。
这样的事情显然是行不通的:
public class MyWorker extends Worker {
private BluetoothLeScanner mBluetoothLeScanner;
@Override
public Worker.Result doWork() {
mBluetoothLeScanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();
// Pretend there's some bluetooth setup here
// ...
mBluetoothLeScanner.startScan( .. , .. , .. );
return Result.SUCCESS;
}
}
Run Code Online (Sandbox Code Playgroud)
上面我们开始扫描,然后立即超出范围,因此扫描将不会继续。
我们可以使用wait()/ notify()解决这个问题,但是感觉很脏。像这样
public class MyWorker extends Worker {
private BluetoothLeScanner mBluetoothLeScanner;
private final Object mLock = new Object();
private Handler mBackgroundHandler;
private Handler getBackgroundHandler() {
if (mBackgroundHandler == null) {
HandlerThread thread = new HandlerThread("background");
thread.start();
mBackgroundHandler = new Handler(thread.getLooper());
}
return mBackgroundHandler;
}
@Override
public Worker.Result doWork() {
getBackgroundHandler().post(new Runnable() {
@Override
public void run() {
mBluetoothLeScanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();
// Pretend there's some bluetooth setup here
// ...
mBluetoothLeScanner.startScan( .. , .. , mScanCallback);
}
});
getBackgroundHandler().postDelayed(new Runnable() {
@Override
public void run() {
mBluetoothLeScanner.stopScan(mScanCallback);
synchronized (mLock) {
mLock.notify();
}
}
}, 60 * 1000); //stop after a minute
try {
synchronized (mLock) {
mLock.wait();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
return Result.SUCCESS;
}
private ScanCallback mScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
//We found an advertisement
mBluetoothLeScanner.stopScan(mScanCallback);
synchronized (mLock) {
mLock.notify();
}
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
mBluetoothLeScanner.stopScan(mScanCallback);
synchronized (mLock) {
mLock.notify();
}
}
};
@Override
public void onStopped(boolean cancelled) {
if (mBackgroundHandler != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
mBackgroundHandler.getLooper().quitSafely();
} else {
mBackgroundHandler.getLooper().quit();
}
mBackgroundHandler = null;
}
}
}
Run Code Online (Sandbox Code Playgroud)
TLDR:在现代(8.1+)Android中实现正在进行的后台工作的最佳方法是什么?考虑到Worker / WorkManager的体系结构,这种正在进行的后台工作确实被Google淘汰了。Worker中的wait()/ notify()模式是否可以接受,还是该解决方法被系统杀死?
任何提示将不胜感激。
编辑:
我希望避免使用前台服务+正在进行的通知。答案在这里似乎有前途的,但它的Android 7.1显然修补。在运行Android 9的手机上,将无线BLE耳机从手机壳中取出后几乎可以立即连接。耳机供应商未运行前台服务(至少在不可见的情况下-没有持久通知)来检测广告。我不知道他们如何可靠地做到这一点。
WorkManager不适合连续工作-这将是前台服务的用例。
但是,通过引入BLE扫描,该BluetoothLeScanner.startScan(List<ScanFilter>, ScanSettings, PendingIntent)方法不需要您的应用程序就可以在API 26+设备上连续运行,这使您可以将a注册PendingIntent为回调,仅在扫描结果可用时才启动应用程序。
对于早期版本的Android,您需要一个持续运行的服务来维持活动扫描。