Android BLE: onCharacteristicRead () parece estar bloqueado por subprocesos

Estoy implementando una serie de lecturas características contra un dispositivo BLE. Debido a que readCharacteristic() ejecuta de forma asincrónica, y porque tenemos que esperar hasta que se complete antes de emitir otra llamada de "lectura", utilicé un bloqueo para wait() y luego en 'onCharacteristicRead() .

Cuando wait() después de llamar a readCharacteristic() , nunca recibo una llamada a onCharacteristicRead() . Si no wait() , entonces recibo una llamada a onCharacteristicRead() y se informa del valor correcto.

Aquí está el código relevante que parece bloquear la devolución de llamada a onCharacteristicRead() :

 private void doRead() { //....internal accounting stuff up here.... characteristic = mGatt.getService(mCurrServiceUUID).getCharacteristic(mCurrCharacteristicUUID); isReading = mGatt.readCharacteristic(characteristic); showToast("Is reading in progress? " + isReading); showToast("On thread: " + Thread.currentThread().getName()); // Wait for read to complete before continuing. while (isReading) { synchronized (readLock) { try { readLock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { showToast("onCharacteristicRead()"); showToast("On thread: " + Thread.currentThread().getName()); byte[] value = characteristic.getValue(); StringBuilder sb = new StringBuilder(); for (byte b : value) { sb.append(String.format("%02X", b)); } showToast("Read characteristic value: " + sb.toString()); synchronized (readLock) { isReading = false; readLock.notifyAll(); } } 

Si simplemente eliminar la sentencia while() anterior, obtengo correctamente la devolución de llamada de lectura. Por supuesto, eso me impide esperar para hacer más lee, así que no puedo seguir adelante sin esperar.

Dado que el readCharacteristic() es asíncrono, ¿por qué la ejecución del hilo llamante tiene algo que ver con la capacidad de hacer realmente la lectura, o la capacidad de llamar a la devolución de llamada?

Para hacer las cosas más confusas, muestro un brindis que identifica el hilo cuando llamo readCharacteristic() , así como cuando onCharacteristicRead() es invocado. Estos 2 subprocesos tienen nombres diferentes. Pensé que tal vez la llamada de llamada se invocó en el hilo de llamada por alguna razón, pero que no parece ser el caso. Entonces, ¿qué está pasando aquí con el enhebrado?

2 Solutions collect form web for “Android BLE: onCharacteristicRead () parece estar bloqueado por subprocesos”

El problema aquí parece ser un problema oscuro con el enhebrado y no se puede ver en mi poste original porque no fijé bastante del historial de la llamada para verlo. Voy a explicar lo que he encontrado aquí en caso de que los efectos de otra persona.

El historial de llamadas completo que conduce a mi problema fue algo como esto:

  1. Iniciar Le Scan
  2. Encuentra el dispositivo que me interesa
  3. Conectar al servidor GATT del dispositivo (que devuelve un cliente GATT, y donde proveo un BluetoothGattCallback para todas las llamadas de comunicación asíncrona)
  4. Dile al cliente del GATT que discoverServices()
  5. Un momento después, el sistema BLE invoca el servicio onServicesDiscovered()
  6. Ahora estoy listo para comenzar a leer las características porque los datos del servicio están cargados, así que aquí es donde invoco ese método doRead() en mi mensaje original
  7. Dígale al cliente del GATT que readCharacteristic()
  8. Ir a dormir hasta que se hace la lectura —- Aquí es donde se produce el punto muerto, pero se supone que:
  9. Un momento después, el sistema BLE invoca la función onCharacteristicRead() mi callbacck,
  10. Notificar a todos los hilos en espera
  11. Vuelva al paso 7 y repita

Primer error:

Originalmente mi método onServicesDiscovered() se parecía a esto:

 public void onServicesDiscovered(final BluetoothGatt gatt, int status) { doRead(); } 

Cuando doRead() ejecuta, se va a dormir y por lo tanto bloquear la ejecución. Esto evita que el método de devolución de llamada finalice y aparentemente arme el sistema de comunicación BLE completo.

Segundo error:

Una vez que me di cuenta de la cuestión anterior, cambié el método a lo siguiente:

 public void onServicesDiscovered(final BluetoothGatt gatt, int status) { new Thread(new Runnable() { @Override public void run() { doRead(); } ).start(); } 

Por lo que puedo decir, la versión anterior del método debería funcionar. Estoy creando un nuevo hilo para ejecutar doRead() , así que dormir en doRead() no debería tener ningún impacto en el hilo de BLE. ¡Pero lo hace! Este cambio no tuvo ningún impacto.

———– Editar nota ————–

Después de publicar esto, realmente no podía racionalizar por qué el hilo anónimo antedicho no funcionaría. Así que lo intenté de nuevo, y esta vez funcionó . No estoy seguro de lo que salió mal la primera vez, tal vez me olvidé de llamar a start() en el hilo o algo así …

——— Fin Editar Nota ————

La solución:

Por último, por un capricho, decidí crear un fondo HandlerThread cuando mi clase se instancia (en lugar de girar un Thread anónimo en onServicesDiscovered() ). El método ahora se parece a esto:

 public void onServicesDiscovered(final BluetoothGatt gatt, int status) { mBackgroundHandler.post(new Runnable() { @Override public void run() { doRead(); } ).start(); } 

La versión anterior del método funciona. La llamada a doRead() itera con éxito sobre cada característica como la anterior se lee.

He resuelto este problema agregando el código siguiente

  @Override public void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicWrite(gatt, characteristic, status); new Thread(new Runnable() { @Override public void run() { gatt.readCharacteristic(characteristic); } }).start(); } 
  • Qué cosas se ejecutan en el hilo principal de la interfaz de usuario al abrir una aplicación para Android
  • ¿Cómo utilizar "runOnUiThread (runnable)" dentro del método estático?
  • El procesador de hilos de Android no recibe el mensaje
  • Cómo pasar en dos tipos de datos diferentes a AsyncTask, Android
  • ¿Cómo funciona llamando a Snackbar.make () de un hilo no-UI?
  • ProgressDialog animaciones pausas en grandes setText ()
  • Iniciar nuevo subproceso en Async Task
  • ¿Se matará el hilo antes de que finalice la actividad en Android?
  • Servicio vs IntentService
  • Hace TimerTask ejecutando en nuevo hilo
  • Android: android.view.ViewRoot $ CalledFromWrongThreadException - ¿Cómo resolver el problema?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.