我正在开发一个必须与BLE设备连接的应用程序,在我的代码中,我想使用从API 21(Android 5)实现的新的Scan和ScanCallback for BLE,但我必须保持与Android 4.3的兼容性以及。
所以我以这种方式编写了代码:
if (Build.VERSION.SDK_INT >= 21) {
mLEScanner.startScan(filters, settings, mScanCallback);
} else {
btAdapter.startLeScan(leScanCallback);
}
我已经定义了2个回调,一个用于API 21及更高版本,另一个用于API 18到20:
//API 21
private ScanCallback mScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
BluetoothDevice btDevice = result.getDevice();
connectToDevice(btDevice);
}
public void connectToDevice(BluetoothDevice device) {
if (mGatt == null) {
mGatt = device.connectGatt(context, false, btleGattCallback);
if (Build.VERSION.SDK_INT < 21) {
btAdapter.stopLeScan(leScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
}
}
};
//API 18 to 20
private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
btAdapter.stopLeScan(leScanCallback);
runOnUiThread(new Runnable() {
@Override
public void run() {
mBluetoothGatt = device.connectGatt(context, false, btleGattCallback);
}
});
}
};
我还添加了注释
@TargetApi(21)
但是当我在Android 4.x上启动应用程序时,它立即崩溃,报告无法找到类ScanCallback的错误(仅适用于Android 5及更高版本的那个)。
我该如何解决这个问题?
非常感谢你。 丹尼尔。
答案 0 :(得分:5)
在阅读了几篇文章后,我做了以下几点。以防万一,以下是关于BluetoothLe
的Android文档<强>第一强>
创建两个方法scanLeDevice21
和scanLeDevice18
。在scanLeDevice21
上添加注释@RequiresApi(21)
,其中包含:
表示只应在给定的API级别或更高级别调用带注释的元素。 这与旧的@TargetApi注释的目的相似,但更清楚地表明这是对调用者的要求,而不是习惯于&#34;抑制&#34;方法中超过minSdkVersion的警告。
<强>第二强>
实施每种方法,这是我的代码。
@RequiresApi(21)
private void scanLeDevice21(final boolean enable) {
ScanCallback mLeScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
BluetoothDevice bluetoothDevice = result.getDevice();
if (!bluetoothDeviceList.contains(bluetoothDevice)) {
Log.d("DEVICE", bluetoothDevice.getName() + "[" + bluetoothDevice.getAddress() + "]");
bluetoothDeviceArrayAdapter.add(bluetoothDevice);
bluetoothDeviceArrayAdapter.notifyDataSetChanged();
}
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
}
};
final BluetoothLeScanner bluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(() -> {
mScanning = false;
swipeRefreshLayout.setRefreshing(false);
bluetoothLeScanner.stopScan(mLeScanCallback);
}, SCAN_PERIOD);
mScanning = true;
bluetoothLeScanner.startScan(mLeScanCallback);
} else {
mScanning = false;
bluetoothLeScanner.stopScan(mLeScanCallback);
}
}
/**
* Scan BLE devices on Android API 18 to 20
*
* @param enable Enable scan
*/
private void scanLeDevice18(boolean enable) {
BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice bluetoothDevice, int rssi,
byte[] scanRecord) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
bluetoothDeviceArrayAdapter.add(bluetoothDevice);
bluetoothDeviceArrayAdapter.notifyDataSetChanged();
}
});
}
};
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(() -> {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
<强>第三强>
每当您需要扫描设备时,您都会围绕代码询问您的版本。例如,我有一个RefreshLayout
来显示设备列表。结果如下:
/**
* Refresh listener
*/
private void refreshScan() {
if (!hasFineLocationPermissions()) {
swipeRefreshLayout.setRefreshing(false);
//Up to marshmallow you need location permissions to scan bluetooth devices, this method is not here since is up to you to implement it and it is out of scope of this question.
requestFineLocationPermission();
} else {
swipeRefreshLayout.setRefreshing(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
scanLeDevice21(true);
} else {
scanLeDevice18(true);
}
}
}
就是这样。
忘记扩展,继承你真正需要的课程,如ulusoyca的回答。
答案 1 :(得分:4)
AbstractBluetoothLe
类和IBleScanCallback
界面。 IBleScanCallback
接口是标记接口。换句话说,一个没有方法的界面。如果需要,您还可以添加接口方法。这些方法将对所有类型的scanCallbacks执行相同的功能,即getListOfFoundBleDevices(),clearListOfFoundBleDevices()等。BluetootLeLollipop
类的BluetoothLeJellyBean
和AbstractBluetoothLe
个类。同时创建扩展BluetootLeMarshmallow
类的BluetootLeLollipop
类。 AbstractBluetoothLe
类具有受保护的字段mIBleScanCallback
,这是IBleScanCallback
个对象。 BleScanCallbackBase
。{/ li>的IBleScanCallback
类
LollipopScanCallback
类并实现ScanCallback
接口的IBleScanCallback
类。这个类有一个受保护的字段scanCallback
,它将被实例化为BleScanCallbackBase
个对象。同时创建扩展MarshmallowScanCallback
类的LollipopScanCallback
类。JellyBeanScanCallback
并实施BleScanCallbackBase
BluetoothAdapter.LeScanCallback
类
BleScanCallbackBase
中覆盖方法:onScanCallback(...)
LollipoScanCallback
覆盖onScanResult(int callbackType, ScanResult result)
并在此方法内部调用onScanCallback(...)
对象的方法scanCallback
。JellyBeanScanCallback
覆盖onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord)
并在此方法内部调用onScanCallback(...)
onScanCallback(...)
类BleScanCallbackBase
方法中找到设备时,需要做任何事情。答案 2 :(得分:0)
您的代码崩溃了,因为它正在创建匿名内部类。因此在运行时它没有找到sCanCallback类。
尝试以下方式并分享结果。在您尝试此操作之前,请确保您对回调(ScanCallback)发表评论。
if (Build.VERSION.SDK_INT >= 21) {
mLEScanner.startScan(filters, settings, new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
BluetoothDevice btDevice = result.getDevice();
connectToDevice(btDevice);
}
public void connectToDevice(BluetoothDevice device) {
if (mGatt == null) {
mGatt = device.connectGatt(context, false, btleGattCallback);
if (Build.VERSION.SDK_INT < 21) {
btAdapter.stopLeScan(leScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
}
}
};
} else {
btAdapter.startLeScan(leScanCallback);
}
答案 3 :(得分:0)
我想分享我的想法,以解决API 21以下设备上的崩溃问题。ScanCallback
类具有API 21的支持。因此,当您编写代码以在扫描代码中实现ScanCallback时,它将导致情人API崩溃。我已通过以下方式对其进行了修复:
我创建了一个新的抽象类,它扩展了ScanCallback类,如下所示:
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public abstract class AppScanCallback extends ScanCallback {}
现在我在我的BluetoothService类中使用该类实例,如下所示:
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private AppScanCallback mScanCallback;
并按如下所示使用此变量:
public void startBleScan() {
if (isEnabled()) {
if (Build.VERSION.SDK_INT < 21) {
_bluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mLEScanner = _bluetoothAdapter.getBluetoothLeScanner();
settings = new ScanSettings.Builder()
.build();
filters = new ArrayList<>();
mScanCallback = new AppScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
if (Build.VERSION.SDK_INT >= 21) {
BluetoothDevice btDevice = result.getDevice();
onLeScanResult(btDevice, result.getScanRecord().getBytes());
}
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
for (ScanResult sr : results) {
Log.i("ScanResult - Results", sr.toString());
}
}
@Override
public void onScanFailed(int errorCode) {
Log.e("Scan Failed", "Error Code: " + errorCode);
}
};
mLEScanner.startScan(filters, settings, mScanCallback);
}
}
}
并停止扫描
public void stopBLEScan() {;
if (Build.VERSION.SDK_INT < 21) {
_bluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
}
希望它会对您有所帮助。