write things low example devices code ble android bluetooth bluetooth-lowenergy android-bluetooth

things - Código de Android Low Energy Bluetooth compatible con API>=21 AND API<21



bluetooth le gatt (3)

Estoy desarrollando una aplicación que debe conectarse con un dispositivo BLE, en mi código deseo usar el nuevo Scan y ScanCallback para BLE implementado desde API 21 (Android 5) pero tengo que mantener la compatibilidad con Android 4.3 y superior.

Así que escribí el código, por ejemplo, de esta manera:

if (Build.VERSION.SDK_INT >= 21) { mLEScanner.startScan(filters, settings, mScanCallback); } else { btAdapter.startLeScan(leScanCallback); }

Y he definido las 2 devoluciones de llamada, una para API 21 y superior, y otra para API de 18 a 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); } }); } };

También agregué la anotación

@TargetApi(21)

pero cuando ejecuto la aplicación en Android 4.x se bloquea inmediatamente y se informa del error de que no se puede encontrar la clase ScanCallback (la que se pretende usar solo con Android 5 y versiones posteriores).

¿Como puedo resolver esto?

Muchas gracias. Daniele.


Tu código se bloquea porque está creando una clase interna anónima. Por lo tanto, en tiempo de ejecución no encuentra esa clase sCanCallback.

Pruebe a continuación y comparta el resultado. Antes de intentar esto, asegúrese de comentar la devolución de llamada (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); }


  1. Cree la clase AbstractBluetoothLe y la interfaz IBleScanCallback . IBleScanCallback interfaz IBleScanCallback es una interfaz de marcador. En otro refrán, una interfaz sin métodos. También puede agregar métodos a la interfaz si lo necesita. Estos métodos harán la misma funcionalidad para todo tipo de scanCallbacks, es decir, getListOfFoundBleDevices (), clearListOfFoundBleDevices (), etc.
  2. Cree las clases BluetoothLeJellyBean y BluetoothLeJellyBean que extienden la clase AbstractBluetoothLe . Cree también BluetootLeMarshmallow clase BluetootLeMarshmallow que amplía BluetootLeLollipop clase BluetootLeLollipop . AbstractBluetoothLe clase AbstractBluetoothLe tiene el campo protegido mIBleScanCallback que es un objeto IBleScanCallback .
  3. Cree la clase BleScanCallbackBase que implementa IBleScanCallback .
  4. Cree la clase LollipopScanCallback que ScanCallback clase ScanCallback e implemente la interfaz IBleScanCallback . .Esta clase tiene un campo protegido scanCallback que se instanciará como objeto BleScanCallbackBase . Crear también la clase MarshmallowScanCallback que amplía la clase LollipopScanCallback .
  5. Cree la clase JellyBeanScanCallback que amplíe BleScanCallbackBase e implemente BluetoothAdapter.LeScanCallback
  6. En BleScanCallbackBase anula el método: onScanCallback(...)
  7. En LollipoScanCallback anule onScanResult(int callbackType, ScanResult result) y dentro de este método llame al método onScanCallback(...) del objeto scanCallback .
  8. En JellyBeanScanCallback anula onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) y dentro de este método llama onScanCallback(...)
  9. Finalmente, haga lo que sea necesario cuando se encuentre un dispositivo en el onScanCallback(...) de la clase BleScanCallbackBase .

En resumen, lea acerca de la composición sobre la herencia: sé que esta no es una respuesta a su pregunta, pero esta es una forma clara de lo que quiere lograr al final. Aquí está el diagrama de clases:


Después de leer varios mensajes, hice lo siguiente. Por si acaso, aquí está la documentación de Android sobre BluetoothLe

primero

Cree dos métodos, uno scanLeDevice21 y scanLeDevice18 . En scanLeDevice21 agregue la anotación @RequiresApi(21) que dice:

Indica que el elemento anotado solo debe invocarse en el nivel API dado o superior. Esto es similar en propósito a la anterior anotación @TargetApi, pero expresa más claramente que este es un requisito para la persona que llama, en lugar de ser utilizado para "suprimir" las advertencias dentro del método que exceden la versión minSdkVersion.

Segundo

Implementa cada método, aquí está mi código.

@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); } }

Tercero

Cada vez que necesite escanear dispositivos, rodeará su código y le preguntará qué versión es usted. Por ejemplo, tengo un RefreshLayout para mostrar la lista de dispositivos. Este es el resultado:

/** * 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); } } }

Y eso es.

Olvídate de extender clases de subclases que realmente no necesitas como respuesta ulusoyca.