英文:
android BTLE scan callback seemingly not called
问题
我想在一个 ViewModel 中运行 BTLE 扫描。我不确定这是否是最佳方法,但这对我来说是一个很好的学习实验。当我在一个更简单的设置中运行扫描时,我成功地列出了我的蓝牙设备。
在 Manifest 中设置了权限 BLUETOOTH
、BLUETOOTH_ADMIN
和 ACCESS_COARSE_LOCATION
。
在我的主设置活动中,我有一个 checkPermissions
方法,用于检查权限,并在需要时请求权限。我还重写了 onRequestPermissionsResult
。位置权限显示在我的应用程序的权限中。这些方法或多或少是从开源项目中复制/粘贴来的(参见这里)。
所以嗯,我的扫描不起作用。在我的回调中,日志从未显示在我的日志中。没有错误,我在日志中唯一可疑的事情是这个:D/BluetoothLeScanner: onScannerRegistered() - status=0 scannerId=12 mScannerId=0
。
我的 ViewModel 如下:
// ViewModel 代码
我真的不确定出了什么问题。是不是因为我在 ViewModel 中创建了新的 BluetoothManager
、BluetoothAdapter
和 BluetoothLeScanner
,而与主活动在哪里初始化和请求权限?如果是这样,我如何重新使用这些相同的对象?
谢谢。
英文:
I want to run a BTLE scan within a ViewModel. I'm not sure if this is the best approach but it is a good learning experiment for me. I did manage to successfully list my BT devices when running the scan in a more simple setup.
Permissions BLUETOOTH
BLUETOOTH_ADMIN
and ACCESS_COARSE_LOCATION
are set in the Manifest
.
I have a checkPermissions
method in my main settings activity that checks for permissions, and requests permissions if needed. I also have an override for onRequestPermissionsResult
. The location permissions shows in my app's permissions. Those methods are more or less a copy/paste of open-source projects (see this).
So well, my scan doesn't work. The log in my callback never shows in my logs. There is no error, the only suspicious thing I'm seeing in the logs is this: D/BluetoothLeScanner: onScannerRegistered() - status=0 scannerId=12 mScannerId=0
.
My ViewModel looks like this:
interface ScanningStatus {
void setCurrentlyScanning(boolean updatedStatus);
boolean getCurrentlyScanning();
}
public class SettingsScanningViewModel extends AndroidViewModel {
private MutableLiveData<ArrayList<BluetoothDevice>> mDeviceList;
private ArrayList<BluetoothDevice> mInternalDeviceList;
private MutableLiveData<Boolean> mIsScanning;
private static final String TAG = "viewmodel";
private BluetoothManager mBtManager;
private BluetoothAdapter mBtAdapter;
private BluetoothLeScanner mBleScanner;
private static final long SCAN_PERIOD = 5000;
public SettingsScanningViewModel(Application mApplication) {
super(mApplication);
mDeviceList = new MutableLiveData<>();
mInternalDeviceList = new ArrayList<>();
mIsScanning = new MutableLiveData<>();
mBtManager = (BluetoothManager) mApplication.getSystemService(Context.BLUETOOTH_SERVICE);
mBtAdapter = mBtManager.getAdapter();
mBleScanner = mBtAdapter.getBluetoothLeScanner();
}
MutableLiveData<ArrayList<BluetoothDevice>> getBtDevices() {
return mDeviceList;
}
MutableLiveData<Boolean> getScanningStatus() {
return mIsScanning;
}
private void flushList() {
mInternalDeviceList.clear();
mDeviceList.setValue(mInternalDeviceList);
}
private void injectIntoList(BluetoothDevice btDevice) {
mInternalDeviceList.add(btDevice);
mDeviceList.setValue(mInternalDeviceList);
}
private ScanCallback scanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
Log.d(TAG, "in callback");
BluetoothDevice mDevice = result.getDevice();
if (!mInternalDeviceList.contains(mDevice) && mDevice.getName() != null) {
injectIntoList(mDevice);
}
}
@Override
public void onScanFailed(int errorCode) {
Log.d(TAG, "onScanFailed: " + errorCode);
}
};
private ScanningStatus scanningStatus = new ScanningStatus() {
@Override
public void setCurrentlyScanning(boolean status) {
mIsScanning.setValue(status);
}
public boolean getCurrentlyScanning() {
return mIsScanning.getValue();
}
};
void doBtScan() {
Log.d(TAG, "flush list first");
flushList();
Log.d(TAG, "starting scan with scanCallback " + scanCallback);
scanningStatus.setCurrentlyScanning(true);
mBleScanner.startScan(scanCallback);
Log.d(TAG, "scan should be running for " + SCAN_PERIOD);
Handler handler = new Handler();
handler.postDelayed(() -> {
mBleScanner.stopScan(scanCallback);
scanningStatus.setCurrentlyScanning(false);
}, SCAN_PERIOD);
}
}
I am really not sure what is wrong. Is it because I'm creating new BluetoothManager
, BluetoothAdapter
and BluetoothLeScanner
in my ViewModel compared with the main activity where I initiate and request permissions? If so, how could I re-use these same objects?
Thank you.
答案1
得分: 0
好的,以下是翻译好的内容:
OKKKKKKKKKKKK 又一个尝试了几个小时试图找出问题所在,发帖,然后2分钟后自己找到了。
看起来 ACCESS_COARSE_LOCATION
还不够,需要 ACCESS_FINE_LOCATION
。所以我想我一定在使用不同的 SDK!
谢谢。
英文:
OKKKKKKKKKKKK another instance of trying to find out what's wrong for hours, posting, then 2mn later finding out by myself.
Looks like ACCESS_COARSE_LOCATION
is not enough and ACCESS_FINE_LOCATION
is needed. So I suppose I must be using a different SDK than previously!
Thank you.
答案2
得分: 0
这三个步骤对我有效。
-
应打开GPS(如果尚未打开,请编写一些代码将其打开)。
-
在清单中声明ACCESS_COARSE_LOCATION和ACCESS_FINE_LOCATION权限,并在运行时进行请求。
-
最重要的是下面这个关于ScanSettings的答案:
https://stackoverflow.com/a/53831870/10432212
英文:
These three steps worked for me.
-
GPS should be turned on (write some code to turn it on if not already).
-
both ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION permissions should be declared in manifest and asked at runtime.
-
and the most important is the below answer talking about ScanSettings
专注分享java语言的经验与见解,让所有开发者获益!
评论