BLE Android - 未调用onConnectionStateChange [英] BLE Android - onConnectionStateChange not being called
问题描述
我在尝试连接外围设备时遇到问题。有时回调 onConnectionStateChange(...)
在 BluetoothDevice #connectGatt(...)
之后不会被调用。我想要实现的是用户操作触发的快速和短连接。
I have a problem trying to connect to a peripheral. Sometimes the callback onConnectionStateChange(...)
is not called after BluetoothDevice#connectGatt(...)
. What I'm trying to achieve is fast and short connections triggered by user action.
这种情况大约发生在10次中,没有特定的先前操作。它持续约20至30秒,或直到应用程序被杀死并重新打开。我遵循的正常步骤顺序是:
This situation occurs about 1 in 10 times without specific prior action. It lasts about 20 to 30 seconds or until the application is killed and reopened. The normal sequence of steps I follow is:
- 扫描设备以查找外围设备。
- 呼叫
BluetoothDevice类#connectGatt(...)
。如果连接时间超过1秒,则表示连接卡住,因此无法连接,因此BluetoothDevice #connectGatt(...)
是又叫了一遍。这样做的次数限制为5次。 -
使用
已连接并开始服务发现。newState调用onConnectionStateChange(...)
- 其余操作无故障执行。
- 断开连接后<$ li c $ c>调用BluetoothGatt #close()。
- Scan devices to find the peripheral.
- Call
BluetoothDevice#connectGatt(...)
. If it takes longer than 1 second to connect, it means that the connection is "stuck" and therefore it won't connect, soBluetoothDevice#connectGatt(...)
is called again. This is done with a limit of 5 attempts. onConnectionStateChange(...)
is called withnewState
CONNECTED and begins the services discovery.- The rest of the operations are performed without problems.
- After disconnection
BluetoothGatt#close()
is called.
发生的问题是在第3点。有时 onConnectionStateChange(...)
未被调用。我注意到大多数时候问题都是从特定的行为开始的。在 BluetoothDevice #connectGatt(...)
之后,使用 onConnectionStateChange(...)
> newState CONNECTED,但几乎立即(~40毫秒)再次调用 newStatus
DISCONNECTED。由于状态改变的时间很短,我可以推断设备甚至没有尝试建立连接并将状态更改为DISCONNECTED。
问题在以下时间结束:
The problem that occurs is at point 3. Sometimes onConnectionStateChange(...)
is not called. I have noticed that most of the times the problem starts with a specific behavior. After BluetoothDevice#connectGatt(...)
, onConnectionStateChange(...)
is called with newState
CONNECTED, but almost immediately afterwards (~40 milliseconds) is called again with newStatus
DISCONNECTED. Due to the short time of the status change, I can deduce that the device does not even tried to make the connection and changed the state to DISCONNECTED.
The problem ends when:
- 已经过了20-30秒。在此期间,永远不会调用
onConnectionStateChange(...)
。问题结束时,onConnectionStateChange(...)
被称为应用尝试连接的次数。例如,如果BluetoothDevice #connectGatt(...)
被调用15次,onConnectionStateChange(...)
是调用15次,newState
等于DISCONNECTED。这很奇怪,因为在任何连接尝试中都没有将状态更改为CONNECTED。 - 应用程序被终止并重新启动。
- 20-30 seconds have passed. During this time
onConnectionStateChange(...)
is never called. When the problem ends,onConnectionStateChange(...)
is called the number of times that the app tried to connect. For example, ifBluetoothDevice#connectGatt(...)
is called 15 times,onConnectionStateChange(...)
is called 15 times withnewState
equal to DISCONNECTED. This is curious because never in any of those connection attempts the status changed to CONNECTED. - The app is killed and started again.
SDK18和SDK中出现此错误21 。
This error occurs in SDK18 and 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应用程序可以始终连接没有这个问题。
I think that the peripheral is not relevant, because the iOS app can always connect without this problem.
任何想法?提前致谢。
编辑!
这个回答说:
直接连接的间隔为60ms,窗口为30ms,因此
连接完成得更快。此外,一次只能有一个
直接连接请求待机,并且在30
秒后超时。使用state = 2,
status = 133调用onConnectionStateChange()以指示此超时。
Direct connection has interval of 60ms and window of 30ms so connections complete much faster. Additionally there can only be one direct connection request pending at a time and it times out after 30 seconds. onConnectionStateChange() gets called with state=2, status=133 to indicate this timeout.
所以在这30秒内间隔有一个挂起的连接请求,并在第二个30秒超时。这不太可能,但是,我能做些什么来缩短这个时间吗?或者可能有一个我没有看到的连接失败的解释。谢谢。
So in this 30 seconds interval there is a pending connection request and times out at the second 30. It's unlikely but, is there anything I can do to make this time shorter? Or maybe there is an explanation for the connection failure that I am not seeing. Thanks.
编辑02/03/2016
可能有所帮助的新事物。当问题开始时,就是在 onConnectionStateChange(...)
被调用时, newState
等于~40ms后的DISCONNECTED在 newState
等于CONNECTED的情况下调用,状态为62 = 0x03E。查看此处状态代码表示GATT_CONN_FAIL_ESTABLISH。当我检测到这种状态时,我正在关闭gatt连接,但问题仍然存在。我也试过断开连接。想法?谢谢。
New thing that may help. When the problem starts, that's it when onConnectionStateChange(...)
is called with newState
equal to DISCONNECTED after ~40ms that is called with newState
equal to CONNECTED, the status is 62 = 0x03E. Looking here that status code means GATT_CONN_FAIL_ESTABLISH. When I detect this status I'm closing the gatt connection, but the problem persists. I also tried disconnecting and closing. Ideas? Thanks.
推荐答案
如果有人遇到类似问题,最终通过更改外围设备使用的BLE芯片解决了问题( Arduino的)。在此更改之前,我发现一个解决方法是在每次连接后关闭并打开BLE。解决方案并不完美,但很大程度上提高了连接速度。
If someone is having a similar issue, the problem was finally solved by changing the BLE chip used by the peripheral (arduino). Before that change, a workaround I found was turning off and on the BLE after each connection. The solution was not perfect, but improved the connection rate a lot.
这篇关于BLE Android - 未调用onConnectionStateChange的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!