Reputation: 151
I'm currently reading variables from a Bluetooth device. This obviously takes an undetermined amount of time, so I am using futures (This method is readCharacteristic in my code down below).
More than one read operation cannot take place at a time - if a second read operation is started while a first operation is still in progress, Flutter will throw an error.
My understanding was that chaining futures together using .then() would only allow the next statement to execute when the previous call had finished. This idea seems to be true until I try to read a third value - that is when the error is thrown, because of the overlapping read events.
Here is my code:
readCharacteristic(scanDurationCharacteristic)
.then((list) => sensorScanDuration = list[0].toDouble())
.then((_) {
readCharacteristic(scanPeriodCharacteristic)
.then((list) => sensorScanPeriod = list[0].toDouble());
}).then((_) {
readCharacteristic(aggregateCharacteristic)
.then((list) => sensorAggregateCount = list[0].toDouble());
}).then((_) {
readCharacteristic(appEUICharacteristic)
.then((list) => appEUI = decimalToHexString(list));
}).then((_) {
readCharacteristic(devEUICharacteristic)
.then((list) => devEUI = decimalToHexString(list));
}).then((_) {
readCharacteristic(appKeyCharacteristic)
.then((list) => appKey = decimalToHexString(list));
});
What is a better way to ensure that these read events will not overlap?
Upvotes: 3
Views: 3798
Reputation: 277707
Although R.C Howell answer is correct, prefer using async
/await
keywords instead. This is much more readable and you're less likely to make an error
Future<void> scanBluetooth() async {
sensorScanDuration = (await readCharacteristic(scanDurationCharacteristic))[0].toDouble();
sensorScanPeriod = (await readCharacteristic(scanPeriodCharacteristic))[0].toDouble();
sensorAggregateCount = (await readCharacteristic(aggregateCharacteristic))[0].toDouble();
appEUI = await readCharacteristic(appEUICharacteristic).then(decimalToHexString);
devEUI = await readCharacteristic(devEUICharacteristic).then(decimalToHexString);
appKey = await readCharacteristic(appKeyCharacteristic).then(decimalToHexString);
}
Upvotes: 11
Reputation: 1081
If you would like to chain Futures, you must return
the previous Future from within the then
method of the previous Future.
The documentation says to chain like so,
expensiveA()
.then((aValue) => expensiveB())
.then((bValue) => expensiveC())
.then((cValue) => doSomethingWith(cValue));
Which is the same as,
expensiveA()
.then((aValue) {
return expensiveB();
}).then((bValue) {
return expensiveC();
}).then((cValue) => doSomethingWith(cValue));
As this applies to your case,
readCharacteristic(scanDurationCharacteristic)
.then((list) {
sensorScanDuration = list[0].toDouble();
return readCharacteristic(scanPeriodCharacteristic);
}).then((list) {
sensorScanPeriod = list[0].toDouble());
return readCharacteristic(aggregateCharacteristic);
}).then((list) {
sensorAggregateCount = list[0].toDouble());
return readCharacteristic(appEUICharacteristic);
}).then((list) {
appEUI = decimalToHexString(list));
return readCharacteristic(devEUICharacteristic);
}).then((list) {
devEUI = decimalToHexString(list));
return readCharacteristic(appKeyCharacteristic);
}).then((list) => appKey = decimalToHexString(list));
Upvotes: 7