安卓BLE多连接

9
我正在尝试创建一个应用程序,可以连接并接收来自多个蓝牙低功耗设备的通知。我想知道如何实现这一点。我需要为每个连接单独创建一个线程吗?考虑到API的异步特性,我该如何确保服务被发现和通知设置的顺序是正确的。目前,我正在使用在此处提供的相同结构:https://developer.android.com/guide/topics/connectivity/bluetooth-le.html。这仅适用于单个连接。我能否保留此结构,即在BluetoothLeService类中扩展Service类并绑定到服务。我最近发现Service类是单例模式,那么我该如何创建我的BluetootLeService类的不同实例,并接收广播并注册Broadcast Receiver/Receivers以处理来自适当设备的更改。
3个回答

17

我想知道如何实现这个

要实现多个BLE连接,您需要存储多个BluetoothGatt对象,并将这些对象用于不同的设备。要存储多个BluetoothGatt连接对象,可以使用Map<>

private Map<String, BluetoothGatt> connectedDeviceMap; 

在 Service 的 onCreate 方法中初始化 Map

connectedDeviceMap = new HashMap<String, BluetoothGatt>();

在调用device.connectGatt(this, false, mGattCallbacks);连接GATT服务器之前,请检查设备是否已连接。

  BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(deviceAddress);
  int connectionState = mBluetoothManager.getConnectionState(device, BluetoothProfile.GATT);

  if(connectionState == BluetoothProfile.STATE_DISCONNECTED ){
   // connect your device
   device.connectGatt(this, false, mGattCallbacks);
  }else if( connectionState == BluetoothProfile.STATE_CONNECTED ){
   // already connected . send Broadcast if needed
  }

如果 BluetoothGattCallback 的连接状态为 CONNECTED,则将 BluetoothGatt 对象存储在 Map 中,如果连接状态为 DISCONNECTED,则从 Map 中移除它。

        @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status,
            int newState) {

        BluetoothDevice device = gatt.getDevice();
        String address = device.getAddress();

        if (newState == BluetoothProfile.STATE_CONNECTED) {

            Log.i(TAG, "Connected to GATT server.");

            if (!connectedDeviceMap.containsKey(address)) {
                  connectedDeviceMap.put(address, gatt);
              }
             // Broadcast if needed
            Log.i(TAG, "Attempting to start service discovery:" +
                    gatt.discoverServices());

        } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
            Log.i(TAG, "Disconnected from GATT server.");
            if (connectedDeviceMap.containsKey(address)){
              BluetoothGatt bluetoothGatt = connectedDeviceMap.get(address);
              if( bluetoothGatt != null ){
                   bluetoothGatt.close();
                   bluetoothGatt = null;
              } 
              connectedDeviceMap.remove(address);                
            }
            // Broadcast if needed
        }
    }

类似的,在onServicesDiscovered(BluetoothGatt gatt, int status)方法中,您可以在参数中得到一个BluetoothGatt连接对象,并从那个BluetoothGatt获取设备。还有其他回调方法,比如public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic),您将从gatt获得设备。

当需要writeCharacteristicwriteDescriptor时,请从Map获取BluetoothGatt对象,然后使用该BluetoothGatt对象为不同的连接调用gatt.writeCharacteristic(characteristic)gatt.writeDescriptor(descriptor)

每个连接都需要单独的线程吗?

我认为您并不需要为每个连接使用单独的Thread。只需在后台线程上运行Service即可。

希望这可以帮助到您。


1
是的,我已经在“Service”上完成了所有这些代码。您可以在Service中使用“BluetoothGattCallback”和“Map”。 “Map”仅用于存储单独的“BluetoothGattCallback”对象。如果需要,您可以在类之间共享“Map”。Android“Service”没有多个实例。如果“Service”正在运行并且您再次启动该“Service”,系统不会重新启动“Service”,而只会调用“onStartCommand()”。 - Abu Yousuf
好的,你的意思是将哈希映射存储在服务中,而该服务的单个实例可以处理所有设备。当发送广播以更新我的活动时,我是否可以通过意图区分设备? - IceManStan
将设备地址发送到广播意图。 - Abu Yousuf
从地图中获取gatt并使用该gatt设置通知。我认为读取数据不需要延迟。 - Abu Yousuf
@AbuYousuf,如果我能问一些关于在不同时间连接的多个设备上使用一个Android应用程序的问题-我应该在android studio中定义多个UUID吗?你能帮忙吗 :( ? - swiftlearneer
显示剩余6条评论

0

我从Gatt客户端(中央)这一侧看到了答案。但是,如果你在外围设备这一侧并且需要连接多个中央设备,那么解决这个问题的方法甚至更加简单。

只需像下面提到的那样将它们的地址保留在一个arrayListOf中:

var connectedDevices = arrayListOf<BluetoothDevice>()

当通知特征变化(发送)时,只需指出要发送到的特定设备:

fun send(content: String, deviceIndex: Int) {
    characteristic.setValue(content)
    Log.i("NOTIFY",
        "notifyCharacteristicChanged called: ${
        gattServer.notifyCharacteristicChanged(connectedDevicesArray[deviceIndex], 
            characteristics, 
            true)}")
}

0

Abu Yousuf的回答真的帮了我很多,尤其是因为我在互联网上找不到类似的东西。 我想补充一件我曾经苦恼过的事情:最好不要将你的BluetoothGattCharacteristic保存在全局变量中,因为它对于每个连接的设备都是唯一且不同的。 所以最好在每个操作中检索它,例如当您想要写入新值时:

BluetoothGatt gatt = connectedDeviceMap.get(address);
BluetoothGattCharacteristic localChar = gatt.getService(SERVICE_UUID).getCharacteristic(CHAR_UUID);
localChar.setValue(value);
gatt.writeCharacteristic(localChar);

很高兴听到我的回答对您有所帮助。 - Abu Yousuf

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