Используйте подписку на поток в качестве будущего в Dart/Flutter

#flutter #dart #stream #future

Вопрос:

Я хочу подключить свое приложение Flutter к устройству Bluetooth с помощью библиотеки flutter_blue и вернуть результат (что угодно), когда соединение включено. Но я не понимаю, как это сделать. Вот мой код :

Будущее подключение(устройство BLUETOOTH-устройства) асинхронно { _btDevice = устройство;

 StreamSubscription<BluetoothDeviceState> subscription;
subscription = device.state.listen((event) async {
  if (event != BluetoothDeviceState.connected) {
    await device.connect();
  } else {
    await device.discoverServices().then((value) => _initFeatures(value));
  }
})
  ..onDone(() {
    // Cascade
    print("onDone");
  });

subscription.asFuture();
//subscription.cancel();
 

}

И когда я вызываю эту функцию с

 await newDevice.connect(bluetoothDevice).then((value) => print('OK'));
 

«ОК» пишется перед реальным подключением. _initFeatures, если вы звоните, когда устройство подключено.

Я пытаюсь использовать asFuture из StreamSubscription с помощью onDone, но это ничего не меняет.

Не могли бы вы мне помочь, пожалуйста ?

ОБНОВЛЕНИЕ 12/10 Я работал над другим проектом в течение нескольких месяцев, и когда я возвращаюсь, я не могу решить проблему, поэтому я добавляю полный код. Концепция заключается в том, что виджет класса вызывает подключение будущего в другом классе и должен получить окончание работы.

Виджет

 Future<void> _connectDevice() async {
try {
  widget.device.connect(widget.btDevice!).then((value) => _initValue());
} catch (e) {
  print(e);
}
 

}

_initValue () — это метод для создания остальной части экрана

и будущее соединяется()

   Future connect(BluetoothDevice device) async {
_btDevice = device;

StreamSubscription<BluetoothDeviceState> subscription;
subscription = device.state.listen((event) async {
  if (event != BluetoothDeviceState.connected) {
    await device.connect();
  } else {
    await device
        .discoverServices()
        .then((value) => _initFeatures(value))
        .then((value) => print("OK"));
  }
});

await subscription.asFuture();
await subscription.cancel();
 

}

Чего бы я хотел, так это чтобы будущее заканчивалось, когда print("OK") вызывается, в порядке .then((value) => _initValue()); вызова. Проблема только в этом конце. Возможно, это не самый лучший способ реализации такого рода решений.

Комментарии:

1. Я не знаком с тем, как package:flutter_blue предполагается использовать, но Stream.listen ожидается, что 1. onData обратный вызов вернется void . Это означает, что его возвращаемое значение будет проигнорировано, поэтому, если вы передадите асинхронный обратный вызов, не будет прямого способа узнать, когда этот обратный вызов завершится. 2. Ваш пример вызывает subscription.asFuture() , но не await делает этого, поэтому ничто не будет ждать завершения подписки.

2. Кроме того, это не обязательно проблема, но обычно непоследовательно использовать оба await и Future.then . await это синтаксический сахар для создания Future.then обратного вызова для вас. Просто используй await .

3. Я знаю, что для нецелесообразности сочетать ожидание и затем, но иногда (например, с ShowDialog) кажется, что только ожидания недостаточно

4.Это поздно для игры, но, пожалуйста, обратите внимание, что StreamSubscription.listen перезаписывает обратные вызовы onDone и onError, поэтому вызов после прослушивания устраняет обратный вызов onDone, который вы определили в первой части вашего фрагмента

5. Наконец-то я нахожу решение. В _connectDevice я отправил обратный вызов в будущее, который является методом, который я хотел, чтобы мне перезвонили, и когда подписка на поток завершена, он запускает обратный вызов