A
A
Anton Akimov2017-10-31 11:48:09
Android
Anton Akimov, 2017-10-31 11:48:09

Why do BLE callbacks "interrupt" the execution of the handler's code?

In my Android application, I work with BLE. I make requests to a remote device and receive asynchronous responses from it in callbacks.
At the same time, I use handler.postDelayed() which closes the connection after a given time if the device is not responding.

It looks like this
1) делаем запрос к устройству
2) если в течение 10 сек. получаем ответ, продолжаем работу
3) делаем новый запрос
4) если в течение 10 сек. ответа нет, закрываем соединение
5) завершаем работу

So, the other day, the handler sequentially worked for me, completing the work, and then (after 36 milliseconds) I received a response from the device (which no one was waiting for).
The log ended up looking like this
1) сделали запрос
2) ответ не пришёл, закрываем соединение
3) ответ ПРИШЁЛ, пытаемся продолжать работу

In short, the callback executed without waiting for the handler to finish executing. Although, if I understand correctly, they both must be executed in the same thread and cannot "interrupt" each other. Can anyone explain how this might work?
Excerpts from source
Подключаемся к устройству:
poll = true;
deviceNumber = 0;
characteristicValues = new String[bleDevices.size()];
characteristicValues[deviceNumber] = "ERROR";   // в случае успеха "ERROR" заменится на значение характеристики
handler.postDelayed(responseWaiting, RESPONSE_TIMEOUT); //RESPONSE_TIMEOUT=10000
bleDevices.get(deviceNumber).connectGatt(appContext, false, bluetoothGattCallback);

Получаем статус подключения и обрабатываем его:
private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            handler.removeCallbacks(responseWaiting);
            currentGatt = gatt;
            switch (newState) {
                case BluetoothGatt.STATE_CONNECTED:
                    if (poll) {
                        if (status == BluetoothGatt.GATT_SUCCESS) {
                            handler.postDelayed(responseWaiting, RESPONSE_TIMEOUT);
                            gatt.discoverServices();
                        } else {
                            nextDevice();
                        }
                    } else {
                        handler.postDelayed(disconnectWaiting, RESPONSE_TIMEOUT);
                        currentGatt.disconnect();
                    }
                    break;
                case BluetoothGatt.STATE_DISCONNECTED:
                    if (poll) {
                        nextDevice();
                    } else {
                        currentGatt.close();
                    }
                    break;
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            //…
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            //…
        }
    };

Подключение к следующему устройству:
private void nextDevice() {
        currentGatt.close();
        deviceNumber++;
        if (deviceNumber < bleDevices.size()) {
            characteristicValues[deviceNumber] = "ERROR";   // в случае успеха "ERROR" заменится на значение характеристики
            handler.postDelayed(responseWaiting, RESPONSE_TIMEOUT);
            bleDevices.get(deviceNumber).connectGatt(appContext, false, bluetoothGattCallback);
        } else {
            fireListeners();
        }
    }

Завершение опроса и отправка результатов внешнему слушателю:
private void fireListeners() {
        for (BLEClientListener bleClientListener : bleClientListeners) {
            if (poll) {
                poll = false;
                bleClientListener.onValuesReceived(characteristicValues);
            }
        }
    }

Answer the question

In order to leave comments, you need to log in

2 answer(s)
A
Anton Akimov, 2019-05-08
@antaki93

Because work with BLE takes place in a separate service thread (the system itself creates it, and this is the only correct approach for working with any network). And callbacks, respectively, are also called in another thread. You can use the same Handler or BroadcastReceivers to interact with the UI thread. And use your own status flags, of course (like ETA_SHTUKA_CONNECTED, ETA_SHTUCA_WAITING).

V
Vadim Ushakov, 2017-10-31
@Nightmare1

Probably the request arises in a separate flow? Try to introduce a timeout function for example, but in general it is desirable that you show the code in which this happens, because it is not clear on the fingers.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question