11

BLE 장치에 대한 일련의 특성 읽기를 구현 중입니다. readCharacteristic()은 비동기 적으로 실행되기 때문에 다른 "읽기"호출을하기 전에 완료해야 할 때까지 기다려야하므로 wait()에 대한 잠금을 사용하고 다시 'onCharacteristicRead()에 I notify() 잠금을 사용합니다.Android BLE : onCharacteristicRead()가 스레드에 의해 차단 된 것으로 나타납니다.

readCharacteristic()을 호출 한 후 I wait()을 호출하면 onCharacteristicRead()으로 전화를받지 않습니다. wait()이 없다면 onCharacteristicRead()으로 전화를 걸면 올바른 값이보고됩니다. 단순히 위의 while() 문을 제거하면

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

, 나는 성공적으로 읽기 콜백을 얻을 :

여기 onCharacteristicRead()에 콜백을 차단하는 것 관련 코드입니다. 물론, 그로 인해 추가 읽기를 기다리는 것을 막을 수 있으므로 기다리지 않고 앞으로 나아갈 수 없습니다.

readCharacteristic()이 비동기 적이기 때문에 호출하는 스레드를 실행하면 실제로 읽는 기능 또는 콜백을 호출 할 수있는 기능과 관련이 있습니다.

좀 더 혼란스럽게 만들기 위해 readCharacteristic()을 호출 할 때뿐만 아니라 onCharacteristicRead()을 호출 할 때 스레드를 식별하는 축하를 보여줍니다. 이 두 스레드는 서로 다른 이름을 가지고 있습니다. 어떤 이유로 호출 스레드에서 콜백이 호출 된 것일 수도 있지만 그 경우는 아닌 것으로 보입니다. 그럼 스레딩으로 무엇이 진행되고 있습니까?

답변

16

여기서 문제는 스레딩에 대한 모호한 문제인 것으로 보이며 전화 기록을 충분히 게시하지 않았기 때문에 원래 게시물에서 볼 수 없습니다. 다른 사람들에게 영향을 줄 수 있기 때문에 내가 여기에서 발견 한 것을 설명 할 것입니다.

내 문제로 이어지는 전체 통화 내역이 같은 갔다 :

  1. 시작 르 스캔을
  2. 나는 GATT 클라이언트를 반환 장치의 GATT 서버에 대한
  3. 연결 (신경
  4. 찾기 장치, 및 모든 비동기 통신 호출에 대해 BluetoothGattCallback을 제공하는 곳)
  5. GATT 클라이언트에 discoverServices()
  6. 나중에 BLE 시스템은 내 callb ACK의 onServicesDiscovered()
  7. 가 지금은 서비스 데이터가로드되어 있기 때문에 특성을 읽기 시작 준비, 그래서 이것이 내가 내 원래의 게시물에 doRead() 방법
  8. 때까지 잠을 readCharacteristic()
  9. 갈 수있는 GATT 클라이언트에게 있음을 호출하는 곳이다 읽기는에 교착 상태가 발생하는 곳입니다 ---- 을 수행하지만, 그 가정한다 :
  10. 순간 후, BLE 시스템 내 callbacck의 onCharacteristicRead()
  11. 모든 대기 스레드를 통보 호출

먼저 실수를 7 단계를 반복 다시 이동

원래 내 onServicesDiscovered() 방법이처럼 보였다 :

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

doRead()이 실행, 잠을 따라서 실행을 차단하는 것입니다 . 이렇게하면 콜백 메서드가 완료되지 않고 전체 BLE 통신 시스템이 완전히 종료됩니다.

두 번째 실수는 :

내가 위의 문제를 실현되면, 나는 다음에 방법을 변경 : 지금까지 내가 말할 수있는

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

, 방법의 위의 버전은 작동합니다 . doRead()을 실행할 새 스레드를 만들고 있으므로 doRead()에자는 것이 BLE 스레드에 영향을 미치지 않아야합니다. 하지만 그렇습니다!이 변경 사항은 영향을 미치지 않았습니다.

----------- 편집 참고 --------------

이를 게시 한 후, 난 정말 왜 위의 익명 스레드를 합리화 할 수 없습니다 작동하지 않을 것이다. 그래서 다시 시도해 보았습니다. 이번에는 이 작업을했습니다.. 처음에 무엇이 잘못되었는지 확신하지 못했을 때, start() 전화 또는 실종 된 것을 잊어 버렸을 수 있습니다 ...

마지막으로, 변덕에, 나는하기로 결정 : 솔루션은

--------- 최종 편집 참고 ------------ 내 클래스가 인스턴스화 될 때 배경 HandlerThread을 작성하십시오 (익명 ThreadonServicesDiscovered()으로 돌리는 대신). 방법은 이제 다음과 같습니다.

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

위 버전의 방법이 작동합니다. doRead()에 대한 호출은 이전 특성이 읽힐 때 각 특성을 성공적으로 반복합니다.

+0

를 추가하여이 문제를 해결했다? 나는 또한 비슷한 문제에 직면하고있다. 미리 감사드립니다. – Anukool

+0

'mBackgroundHandler'는 어떻게 초기화됩니까? – Felix

+0

똑같은 것으로 나타났습니다!. writeCharacteristic()에서 디버깅하고 깨고 나면 항상 작동하는 것처럼 보입니다. 나는 이것이 동기화 문제라고 생각한다. – aclokay

2

난 당신이 클래스에 대한 완전한 소스를 제공시겠습니까 다음 코드

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