Reputation: 151
I'm currently trying to wait for a BLE connection to result in one of two outcomes:
Instead of returning a true or false value as desired, null is immediately returned, without waiting for the function to finish.
I'm using dart's Future and async functionality in order to wait for the completion of the connect function. Here is my code below:
BLE Connect method:
static Future<bool> connect(BluetoothDevice d) async {
// Connect to device
Duration timeout = new Duration(seconds: 5);
deviceConnection = _flutterBlue.connect(d, timeout: timeout).listen((s) {
deviceState = s;
if (s == BluetoothDeviceState.connected) {
device = d;
device.discoverServices().then((s) {
... Some service discovery stuff ...
});
}
}, onDone: () {
return deviceState == BluetoothDeviceState.connected;
});
}
Where the connect method is being called from:
bool isConnected = await FlutterBLE.connect(device);
if(isConnected) {
... Do some stuff ...
} else {
... Do some other stuff ...
}
What am I doing wrong here?
Upvotes: 4
Views: 6383
Reputation: 71623
As Günther Zöchbauer has pointed out, the mistake is in the onDone
part. You are returning a value there that nobody will ever see, and you are no returning anything from the surrounding function.
You are inside an async function, so you can use await for
to iterate the stream.
You also want to stop listening to the stream the first time you get a connection event, because you only care about the first connection. The stream of connection events itself never stops.
static Future<bool> connect(BluetoothDevice d) async {
// Connect to device
Duration timeout = const Duration(seconds: 5);
await for (var s in _flutterBlue.connect(d, timeout: timeout)) {
deviceState = s;
if (s == BluetoothDeviceState.connected) {
device = d;
device.discoverServices().then((s) {
... Some service discovery stuff ...
});
return true;
}
}
// The stream ended somehow, there will be no further events.
return false;
}
If you don't want to use await for
(and not using an async function to begin with), I would recommend using firstWhere
to find the first connection (if any) over listen
:
static Future<bool> connect(BluetoothDevice d) {
// Connect to device
Duration timeout = const Duration(seconds: 5);
return _flutterBlue.connect(d, timeout: timeout).firstWhere((s) {
return s == BluetoothDeviceState.connected;
}, orElse: () => null).then((s) {
if (s == null) return false;
deviceState = s;
device = d;
device.discoverServices().then((s) {
//... Some service discovery stuff ...
});
return true;
});
It's also slightly suspicious that nobody waits for the future returned by device.discoverServices().then(...)
. Make sure that this is correct.
Upvotes: 3
Reputation: 657108
The onDone
part doesn't do what you expect.
Try instead:
static Future<bool> connect(BluetoothDevice d) async {
// Connect to device
Duration timeout = new Duration(seconds: 5);
await _flutterBlue.connect(d, timeout: timeout).listen((s) {
deviceState = s;
if (s == BluetoothDeviceState.connected) {
device = d;
device.discoverServices().then((s) {
... Some service discovery stuff ...
});
}
}).asFuture();
return deviceState == BluetoothDeviceState.connected;
}
Upvotes: 0