Ответ 1
Проблема здесь кажется неясной проблемой с потоковой обработкой, и ее нельзя увидеть в моем первоначальном сообщении, потому что я не опубликовал достаточно истории вызовов, чтобы увидеть ее. Я объясню, что я нашел здесь, если это повлияет на кого-то другого.
Полная история вызовов, ведущих к моей проблеме, прошла примерно так:
- Запустить Le Scan
- Найти устройство, которое меня волнует
- Подключиться к устройству GATT-серверу (который возвращает клиент GATT и где я предоставляю BluetoothGattCallback для всех асинхронных вызовов связи)
- Сообщите клиенту GATT
discoverServices()
- Через мгновение система BLE вызывает мой обратный вызов
onServicesDiscovered()
- Теперь я готов начать считывать характеристики, потому что загружаются данные службы, поэтому здесь я вызываю этот метод
doRead()
в своем исходном сообщении - Скажите клиенту GATT
readCharacteristic()
- Идите спать до тех пор, пока не будет прочитано ---- Это где тупик, но его предполагается:
- Через мгновение система BLE вызывает мой callbacck
onCharacteristicRead()
- Уведомлять обо всех ожидающих потоках
- Вернитесь к шагу 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
, когда мой класс получает экземпляр (вместо поворота анонимного Thread
в onServicesDiscovered()
). Теперь метод выглядит следующим образом:
public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
mBackgroundHandler.post(new Runnable() {
@Override
public void run() {
doRead();
}
).start();
}
Вышеупомянутая версия метода работает. Вызов doRead()
успешно повторяется по каждому признаку, поскольку предыдущий читается.