Android 4.3:如何连接多个蓝牙低能耗设备
我的问题是:安卓4.3(客户端)能否与多个BLE设备(服务器)建立活动连接?如果是,我如何实现它? 到目前为止我做了什么 我尝试评估使用BLE和Android 4.3 BLE API可以实现的吞吐量。此外,我还试图找出有多少设备可以同时连接和激活。我使用Nexus7(2013),安卓4.4作为主控,TI CC2540 Keyfob作为从控 我为从机编写了一个简单的服务器软件,它通过BLE通知传输10000个20字节的数据包。我的Android应用程序基于Bluetooth SIG的 它适用于一台设备,我可以以7.5毫秒的连接间隔实现约56 kbit的有效负载吞吐量。要连接到多个从属设备,我遵循了一位北欧员工的建议,他在报告中写道: 是的,一个应用程序可以处理多个从机。您需要使用一个BluetoothGatt实例来处理每个从机。您还需要为连接到的每个从机指定BluetoothGattCallback 所以我试过了,它部分有效。我可以连接到多个从属服务器。我还可以注册多个从属服务器上的通知。当我开始测试时,问题就开始了。我首先收到来自所有从属设备的通知,但经过几次连接间隔后,只有来自一个设备的通知通过。大约10秒钟后,其他从属设备断开连接,因为它们似乎达到连接超时。有时,我从测试一开始就只收到一个从机的通知 我还尝试通过读取操作访问属性,结果相同。读了几遍之后,只有一台设备的答案出来了 我知道在这个论坛上有一些类似的问题:,或者。但这些答案都没有让我明白,如果可能的话,以及如何做到这一点Android 4.3:如何连接多个蓝牙低能耗设备,android,bluetooth-lowenergy,
android,Android,Bluetooth Lowenergy,
android,我的问题是:安卓4.3(客户端)能否与多个BLE设备(服务器)建立活动连接?如果是,我如何实现它? 到目前为止我做了什么 我尝试评估使用BLE和Android 4.3 BLE API可以实现的吞吐量。此外,我还试图找出有多少设备可以同时连接和激活。我使用Nexus7(2013),安卓4.4作为主控,TI CC2540 Keyfob作为从控 我为从机编写了一个简单的服务器软件,它通过BLE通知传输10000个20字节的数据包。我的Android应用程序基于Bluetooth SIG的 它适用于一台
非常感谢您的建议。不幸的是,当前Android BLE堆栈中的通知有点缺陷。有一些硬编码的限制,我发现一些稳定性问题,即使是一个单一的设备。(我曾经读到,您只能有4个通知……不确定是跨所有设备还是每个设备发送。现在正在尝试查找该信息的来源。) 我会尝试切换到一个轮询循环(比如,每秒钟轮询一次问题项),看看你是否发现自己的稳定性有所提高。我也会考虑切换到一个不同的从设备(比如说HRM或TI SeSONTAG标签),看看是否有一个与从属侧代码有关的问题(除非您可以测试IOS或其他平台的情况,并确认它不是问题的一部分)。
编辑:我自己正在开发一款具有BLE功能的应用程序。我设法连接到多个设备并打开通知的方法是实现延迟 因此,我创建了一个新线程(为了不阻塞UI线程),并在新线程中连接并打开通知 例如,在BluetoothDevice.connectGatt()之后;调用Thread.sleep() 并为读/写和启用/禁用通知添加相同的延迟 编辑 使用这样的等待,这样Android dindn就不会重新启用ANR
public static boolean waitIdle() {
int i = 300;
i /= 10;
while (--i > 0) {
if (true)
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return i > 0;
}
Rain的回答是正确的,当你在Android中使用BLE时,几乎所有事情都需要延迟。我用它开发了几个应用程序,这是非常必要的。通过使用它们,您可以避免大量的崩溃 在我的例子中,我在每个读/写命令之后使用延迟。这样做,您可以确保几乎总是收到来自BLE设备的响应。我这样做:(当然,所有的事情都是在一个单独的线程中完成的,以避免在主线程上做太多的工作) 或: 当您读/写一行中的几个特征时,这非常有用。。。由于Android的速度足够快,几乎可以立即执行命令,如果不在命令之间使用延迟,可能会出现错误或不一致的值 希望它能帮助你,即使它不是你问题的答案。重新审视问题:我仍然在使用延迟 概念:在每一个引发问题的重大行动(例如,会议、服务发现、写入、读取)之后,都需要一个协议。另外,请看一看BLE上的谷歌示例,了解广播应该如何发送,并获得一些一般性的理解等等 首先,(或)对于Bluetooth设备,使用所需设备填充连接队列,并调用initConnection() 看看下面的例子
private Queue<BluetoothDevice> connectionQueue = new LinkedList<BluetoothDevice>();
public void initConnection(){
if(connectionThread == null){
connectionThread = new Thread(new Runnable() {
@Override
public void run() {
connectionLoop();
connectionThread.interrupt();
connectionThread = null;
}
});
connectionThread.start();
}
}
private void connectionLoop(){
while(!connectionQueue.isEmpty()){
connectionQueue.poll().connectGatt(context, false, bleInterface.mGattCallback);
try {
Thread.sleep(250);
} catch (InterruptedException e) {}
}
}
注意:发送广播(意图)可能需要这样做:
Context context = activity.getBaseContext();
context.sendBroadcast(intent);
然后广播被接收
在广播接收器中完成您想要的任何操作后,我将继续:
private Queue<BluetoothGatt> serviceDiscoveryQueue = new LinkedList<BluetoothGatt>();
private void initServiceDiscovery(){
if(serviceDiscoveryThread == null){
serviceDiscoveryThread = new Thread(new Runnable() {
@Override
public void run() {
serviceDiscovery();
serviceDiscoveryThread.interrupt();
serviceDiscoveryThread = null;
}
});
serviceDiscoveryThread.start();
}
}
private void serviceDiscovery(){
while(!serviceDiscoveryQueue.isEmpty()){
serviceDiscoveryQueue.poll().discoverServices();
try {
Thread.sleep(250);
} catch (InterruptedException e){}
}
}
private Queue servicesdiscoveryqueue=new LinkedList();
私有void initServiceDiscovery(){
如果(serviceDiscoveryThread==null){
serviceDiscoveryThread=新线程(新可运行(){
@凌驾
公开募捐{
服务发现();
ServiceDiscoveryRead.interrupt();
serviceDiscoveryThread=null;
}
});
servicescoverythread.start();
}
}
私有void服务发现(){
而(!serviceDiscoveryQueue.isEmpty()){
serviceDiscoveryQueue.poll().discoverServices();
试一试{
睡眠(250);
}捕获(中断异常e){}
}
}
同样,在成功发现服务后,调用。同样,我向BroadcastReceiver发送了一个意图(这次使用不同的操作字符串),现在您可以开始读取、写入和启用通知/指示了。。。
P.S.如果您正在使用多台设备,请确保开始阅读、写作等。。。在所有设备都报告其服务已被发现后进行填充。
private Queue<BluetoothGattCharacteristic> characteristicReadQueue = new LinkedList<BluetoothGattCharacteristic>();
private void startThread(){
if(initialisationThread == null){
initialisationThread = new Thread(new Runnable() {
@Override
public void run() {
loopQueues();
initialisationThread.interrupt();
initialisationThread = null;
}
});
initialisationThread.start();
}
}
private void loopQueues() {
while(!characteristicReadQueue.isEmpty()){
readCharacteristic(characteristicReadQueue.poll());
try {
Thread.sleep(BluetoothConstants.DELAY);
} catch (InterruptedException e) {}
}
// A loop for starting indications and all other stuff goes here!
}
Context context = activity.getBaseContext();
context.sendBroadcast(intent);
public BroadcastReceiver myUpdateReceiver = new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if(BluetoothConstants.ACTION_GATT_CONNECTED.equals(action)){
//Connection made, here you can make a decision: do you want to initiate service discovery.
// P.S. If you are working with multiple devices,
// make sure that you start the service discovery
// after all desired connections are made
}
....
}
}
private Queue<BluetoothGatt> serviceDiscoveryQueue = new LinkedList<BluetoothGatt>();
private void initServiceDiscovery(){
if(serviceDiscoveryThread == null){
serviceDiscoveryThread = new Thread(new Runnable() {
@Override
public void run() {
serviceDiscovery();
serviceDiscoveryThread.interrupt();
serviceDiscoveryThread = null;
}
});
serviceDiscoveryThread.start();
}
}
private void serviceDiscovery(){
while(!serviceDiscoveryQueue.isEmpty()){
serviceDiscoveryQueue.poll().discoverServices();
try {
Thread.sleep(250);
} catch (InterruptedException e){}
}
}
private Queue<BluetoothGattCharacteristic> characteristicReadQueue = new LinkedList<BluetoothGattCharacteristic>();
private void startThread(){
if(initialisationThread == null){
initialisationThread = new Thread(new Runnable() {
@Override
public void run() {
loopQueues();
initialisationThread.interrupt();
initialisationThread = null;
}
});
initialisationThread.start();
}
}
private void loopQueues() {
while(!characteristicReadQueue.isEmpty()){
readCharacteristic(characteristicReadQueue.poll());
try {
Thread.sleep(BluetoothConstants.DELAY);
} catch (InterruptedException e) {}
}
// A loop for starting indications and all other stuff goes here!
}
BluetoothGatt g;
g.writeDescriptor(a);
g.writeDescriptor(b);