FlutterKolja
FlutterKolja

Reputation: 11

Capture a BLE characteristic and assign it to a variable in Flutter

I need to catch a specific value of a characteristic instantly onPress. So I wrote a function for this. The problem is, that I couldn't manage to assign the value to a variable so far. What is the best way to solve the problem?

I'm using the flutter_blue example code below: https://pub.dev/packages/flutter_blue#-readme-tab-

My function is:

  List<int> _testReadCharacteristic(String uuid) {
    List<int> value;
    device.services.forEach((ls) async {
      //Scans the Liste for all services
      ls.forEach((s) async {
        // Scans the List of services for a specific service
        // do something with s
        List<BluetoothCharacteristic> characteristics = s.characteristics;
        for (BluetoothCharacteristic c in characteristics) {
          // Scans all characteristics
          if (c.uuid.toString().toUpperCase().substring(4, 8) == uuid) {
            value = await c.read();
            print('**************** value is: $value');
          }
        }
      });
    });
    return value;
  }

And the code for the Button is:

        RaisedButton(
          onPressed: () {
           capturedValue = _testReadCharacteristic('1100');
          print('***********The captured Value is: $capturedValue');
          },
          child: const Text('Read Characteristic',
              style: TextStyle(fontSize: 20)),
        ),

When I press the button, I get a print of the capturedValue which is Null first. After that I get a print of value which is exactly the value I want to assign to capturedValue. How can I change the order so that I can work with capturedValue?

Upvotes: 1

Views: 962

Answers (1)

Hannes K&#252;ttner
Hannes K&#252;ttner

Reputation: 978

The problem is that List.forEach does not respect / await async functions. That means your variable is never assigned in time but instead returned empty and then assigned after the read completes asynchronously.

You can achieve your intended behavior with you have to convert your _testReadCharacteristic into and sync method as well and await it in your button onPressed handler. Additionally you need to use Future.forEach instead of List.forEach so that the outer method can wait for the result:

List<int> _testReadCharacteristic(String uuid) async {
    List<int> value;
    await Future.forEach(device.services.forEach((ls) async {
        //Scans the Liste for all services
        await Future.forEach(ls, (s) async {
        // Scans the Liste of services for a specific service
        // do something with s
        List<BluetoothCharacteristic> characteristics = s.characteristics;
            for (BluetoothCharacteristic c in characteristics) {
                // Scans all characteristics
                if (c.uuid.toString().toUpperCase().substring(4, 8) == uuid) {
                   value = await c.read();
                   print('**************** value is: $value');
                }
            }
        });
    });
    return value;
}

And finally in your onPressed

capturedValue = await _testReadCharacteristic('1100');

Upvotes: 1

Related Questions