如何防止BluetoothGattCallback在同一时间被执行多次

11

我有一个服务,其中只有一个BluetoothGattCallback的实例。

public class MyService extends Service {

    private BluetoothGattCallback callback;

    @Override
    public void onCreate() {
            super.onCreate();

            callback = new BluetoothGattCallback() {
                      @Override
                      public synchronized void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                              Log.i("onConnectionStateChanged", "Status " + status);                
                              Log.i("onConnectionStateChanged", "New State " + newState);                
                      }
            };
    }

    // registration of bluetooth adapter and blah blah blah


}

当我启动应用程序时,它能正常工作,回调函数只被调用一次,但尝试几次后,它会被调用两次。
示例日志:
10-22 13:29:18.731 26944-26961/redacted.lollipop I/onConnectionStateChange: Status 0
10-22 13:29:18.731 26944-26961/redacted.lollipop I/onConnectionStateChange: New State 2
10-22 13:29:18.731 26944-26961/redacted.lollipop I/onConnectionStateChange: Status 0
10-22 13:29:18.731 26944-26961/redacted.lollipop I/onConnectionStateChange: New State 2

更多示例日志

10-22 13:29:48.836 26944-26961/redacted.lollipop I/onConnectionStateChange: Status 8
10-22 13:29:48.836 26944-26961/redacted.lollipop I/onConnectionStateChange: New State 0
10-22 13:29:48.850 26944-30763/redacted.lollipop I/onConnectionStateChange: Status 8
10-22 13:29:48.850 26944-30763/redacted.lollipop I/onConnectionStateChange: New State 0

应用程序保持激活的时间越长,它被调用的次数就越多。我该如何防止这种情况?


只需在onCreate方法中放置一个日志,并查看在回调被调用之前,该方法被调用了多少次。我认为问题出在服务的概念上。 - Saeed Entezari
或者检查一下你在onCreate()下面提到的那个接收器注册了多少次。 - Saeed Entezari
它只被调用一次。我的做法是调用connectGatt方法,该方法由回调本身同步和锁定,例如:synchronized(callback) { device.connectGatt(getBaseContext(), true, callback, 2); } - Kevin D.
@KevinD。我在Android OS 8.0及以下版本上遇到了同样的问题。每当我收到BLE断开连接/蓝牙关闭/ForegroundService onDestroy回调时,我都会关闭Gatt连接。你能否解决这个问题? 如果可能的话,你可以查看Google问题跟踪器链接以获取更多详细信息https://issuetracker.google.com/issues/135215253 - Ganesh Tikone
@GaneshTikone 看看已接受的答案 - 不幸的是,我最近没有进行过太多的本地开发。 - Kevin D.
1个回答

25

需要记住的一件事是,每次您调用该函数时

bluetoothDevice.connectGatt(context, true, callback);

它创建一个新的bluetoothGatt对象实例。 查看此链接的源代码,你会看到:

         BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this, transport);
         gatt.connect(autoConnect, callback);

一个棘手的问题是如果您的设备断开连接,并且使用connectGatt(context,true,callback)重新连接到它,而不是在以前的bluetoothGatt实例上调用connect(),则会得到两个bluetoothGatt实例,它们都具有对gatt回调的句柄。

最初,我试图通过尝试在重新连接之前关闭和断开蓝牙Gatt来解决问题。

   if (service.bluetoothGatt!=null){
        Log.i("Rides","Closeing bluetooth gatt on disconnect");
        service.bluetoothGatt.close();
        service.bluetoothGatt.disconnect();
        service.bluetoothGatt=null;
    } 

但是这种方法不起作用,我会在某些情况下收到多个onConnectionStateChanged回调。

我解决了这个问题,通过检查是否有一个有效的BluetoothGatt对象,并确保在重新连接时调用connect()方法。

---- 更新的答案 ----

我发现更好的做法是在onConnectionStateChanged回调中调用bluetoothGatt.close()。当你发出断开连接请求时,它会向蓝牙设备发送一个请求断开连接的消息。然后一旦它响应,你就会得到回调,并关闭蓝牙gatt连接。等待回调并且直到完全关闭它才打开另一个gatt连接,似乎可以防止多个gatt对象连接到应用程序。


1
你是如何检查一个有效的bluetoothGatt对象的? - Galya
主要是如果我仍然拥有指向它的指针并且它是同一个蓝牙设备。我最终不得不编写代码来尝试使用上一个,但如果失败了,则使用新的。 - Marc
抱歉伙计 - 我已经离开本地世界很长一段时间了。我会接受这个作为最佳答案,因为它在理论上是正确的。不幸的是,我无法验证,因为我已经离开公司很久了。 - Kevin D.
你说得太对了! 我之前很困惑为什么 onConnectionStateChanged 回调函数会被多次调用。 - Kaveri
你是传奇。非常感谢! - Sangwon Choi
感谢您更新的答案,但是我们是否有共识认为关闭Gatt是处理中间断开连接的最佳方式?在我的看法中,当意图重新连接时重新建立Gatt有点浪费。否则,“connect()”函数的目的是什么?Gatt会出现损坏吗?还有其他需要关闭并重新创建的问题吗? - axa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接