У меня проблема с подключением к периферии. Иногда callback onConnectionStateChange(...)
не вызывается после BluetoothDevice#connectGatt(...)
. То, что я пытаюсь достичь, это быстрые и короткие соединения, вызванные действием пользователя.
Эта ситуация происходит примерно в 1 раз в 10 раз без конкретных действий. Он длится около 20-30 секунд или пока приложение не будет убито и не будет возобновлено. Нормальная последовательность шагов, которые я выполняю, следующая:
- Сканировать устройства, чтобы найти периферийные устройства.
- Вызов
BluetoothDevice#connectGatt(...)
. Если для подключения требуется более 1 секунды, это означает, что соединение "застряло" и, следовательно, оно не будет подключаться, поэтомуBluetoothDevice#connectGatt(...)
вызывается снова. Это делается с ограничением в 5 попыток. -
onConnectionStateChange(...)
вызывается с помощьюnewState
CONNECTED и начинает обнаружение служб. - Остальные операции выполняются без проблем.
- После выключения
BluetoothGatt#close()
.
Проблема, которая возникает, находится в точке 3. Иногда onConnectionStateChange(...)
не вызывается. Я заметил, что в большинстве случаев проблема начинается с определенного поведения. После BluetoothDevice#connectGatt(...)
, onConnectionStateChange(...)
вызывается с newState
CONNECTED, но почти сразу после этого (~ 40 миллисекунд) снова вызывается с newStatus
DISCONNECTED. Из-за короткого времени изменения статуса я могу сделать вывод, что устройство даже не пыталось установить соединение и изменило состояние на DISCONNECTED.
Проблема заканчивается, когда:
- Прошло 20-30 секунд. За это время
onConnectionStateChange(...)
никогда не вызывается. Когда проблема заканчивается,onConnectionStateChange(...)
называется числом раз, которое приложение пыталось подключиться. Например, еслиBluetoothDevice#connectGatt(...)
вызывается 15 раз,onConnectionStateChange(...)
вызывается 15 раз сnewState
равным DISCONNECTED. Это любопытно, потому что ни в одном из этих попыток подключения статус не изменился на CONNECTED. - Приложение убито и снова запустилось.
Эта ошибка возникает в SDK18 и SDK 21.
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
String deviceName = device.getName();
if (deviceName == null) return;
Log.d("BLUETOOTH CONNECTION", "Device found: " + device.getName());
if (mMode == SCAN_MODE) {
mListener.deviceFound(device, rssi, scanRecord);
}
else {
mDevices.put(device.hashCode(), device);
stopScan();
// Samsung devices with SDK 18 or 19 requires that connectGatt is called in main thread.
mHandler.post(new Runnable() {
@Override
public void run() {
Log.d("BLUETOOTH CONNECTION", "Executing first device.connectGatt()");
BluetoothGatt gatt = device.connectGatt(mContext, false, mGattCallback);
retryIfNecessary(device, gatt);
mTryingToConnect = true;
}
});
}
}
private void retryIfNecessary(final BluetoothDevice device, final BluetoothGatt gatt) {
if (isRetryLimitReached()) {
Log.d("BLUETOOTH CONNECTION", "Try count limit reached");
finishConnection(gatt);
mRetryCount = 0;
mListener.error(TIMEOUT);
return;
}
mRetryCount++;
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
Log.d("BLUETOOTH CONNECTION", "Check if it is frozen.");
if (isWorking()) {
Log.d("BLUETOOTH CONNECTION", "Frozen, create new connection.");
BluetoothGatt gatt = device.connectGatt(mContext, false, mGattCallback);
retryIfNecessary(device, gatt);
}
}
}, RETRY_INTERVAL_MS);
}
@Override
public void onConnectionStateChange(final BluetoothGatt gatt, int status, int newState) {
Log.d("BLUETOOTH CONNECTION", "On connection state changed. Device: "+ gatt.getDevice().getAddress());
if (!mConnected && BluetoothGatt.STATE_CONNECTED == newState) {
Log.d("BLUETOOTH CONNECTION", "Connected");
mTryingToConnect = false;
mTryingToDiscoverServices = true;
mConnected = true;
gatt.discoverServices();
}
else if(BluetoothGatt.STATE_DISCONNECTED == newState) {
Log.d("BLUETOOTH CONNECTION", "Disconnected and closing gatt.");
mConnected = false;
gatt.close();
if (!mConnectionFinished && mRetryCount == 0) {
finishConnection(gatt);
}
}
}
Я думаю, что периферийное устройство не актуально, потому что приложение iOS всегда может подключаться без этой проблемы.
Любые идеи? Спасибо заранее.
Edit
Этот ответ говорит, что:
Прямое соединение имеет интервал 60 мс и окно 30 мс, поэтому соединения выполняются намного быстрее. Кроме того, может быть только один прямой запрос на соединение, ожидающий времени, и он истекает после 30 секунд. onConnectionStateChange() вызывается с состоянием = 2, status = 133, чтобы указать этот тайм-аут.
Итак, в этот интервал 30 секунд есть ожидающий запрос на соединение и время ожидания на второй 30. Это маловероятно, но есть ли что-нибудь, что я могу сделать, чтобы сделать это короче? Или, может быть, есть объяснение сбоя подключения, которого я не вижу. Спасибо.
РЕДАКТИРОВАТЬ 02/03/2016
Новое, что может помочь. Когда проблема начинается, что при onConnectionStateChange(...)
вызывается с newState
равным DISCONNECTED после ~ 40 мс, который вызывается с newState
равным CONNECTED, статус равен 62 = 0x03E. Посмотрите здесь, что код состояния означает GATT_CONN_FAIL_ESTABLISH. Когда я обнаруживаю этот статус, я закрываю соединение gatt, но проблема сохраняется. Я также попытался отключить и закрыть. Идеи? Спасибо.