Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/vim/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Flutter Dart和FLAFT异步初始化最佳实践和代码结构-如何在继续之前等待流中的特定条件_Flutter_Dart_Asynchronous_Async Await_Stream - Fatal编程技术网

Flutter Dart和FLAFT异步初始化最佳实践和代码结构-如何在继续之前等待流中的特定条件

Flutter Dart和FLAFT异步初始化最佳实践和代码结构-如何在继续之前等待流中的特定条件,flutter,dart,asynchronous,async-await,stream,Flutter,Dart,Asynchronous,Async Await,Stream,我正在一个dart/Flatter应用程序中初始化一个BLE连接。代码库来自使用 我是异步编程的新手,在进入下一步初始化之前,我一直在努力寻找正确/简洁的方法来等待函数完成,因为所有函数都返回void 当我尝试使函数成为未来函数时,我无法弄清楚如何将其正确应用于流,因为它返回Null并在返回_startScan()的结果之前进入下一步 有效但混乱且绝对不是最佳实践的当前代码: void initState() { super.initState(); _dataToSendText =

我正在一个dart/Flatter应用程序中初始化一个BLE连接。代码库来自使用

我是异步编程的新手,在进入下一步初始化之前,我一直在努力寻找正确/简洁的方法来等待函数完成,因为所有函数都返回void

当我尝试使函数成为未来函数时,我无法弄清楚如何将其正确应用于流,因为它返回Null并在返回_startScan()的结果之前进入下一步

有效但混乱且绝对不是最佳实践的当前代码:

void initState() {
  super.initState();
  _dataToSendText = TextEditingController();
  initBle();
}

void initBle() async {
print('starting scan');
_startScan();

while (true) {
  if (_foundBleUARTDevices.isNotEmpty) {
    print('stopping scan');
    _stopScan();
    break;
  } else {
    print('waiting 3 sec for start scan to complete');
    await Future.delayed(Duration(seconds: 1), () {});
  }
}

while (true) {
  if (!_scanning) {
    print('connecting to module');
    onConnectDevice(0);
    break;
  } else {
    print('waiting  1 sec for Stop scan to complete');
    await Future.delayed(Duration(seconds: 1), () {});
  }
}

while (true) {
  if (_connected) {
    break;
  } else {
    print('waiting 1 sec to connect to module');
    await Future.delayed(Duration(seconds: 3), () {});
  }
}

print('sending first data packet)');
_sendData('18EF9697080100F1FFFE010101');
}
如果我能弄清楚如何在调用的函数中正确地返回Futures,我猜代码应该是这样的

void initBle() async {
  print('starting scan');
  await _startScan();
  print('stopping scan');
  await _stopScan();
  print('connecting to module');
  await onConnectDevice(0);

  print('sending first data packet)');
  _sendData('18EF9697080100F1FFFE010101');
}
或者也许有更好的方法完全完成这个BLE init序列?我是新手,对任何最佳实践都持开放态度

完整代码如下:

    import 'dart:async';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:location_permissions/location_permissions.dart';
import 'dart:io' show Platform;

// This flutter app demonstrates an usage of the flutter_reactive_ble flutter plugin
// This app works only with BLE devices which advertise with a Nordic UART Service (NUS) UUID
Uuid _UART_UUID = Uuid.parse("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");
Uuid _UART_RX = Uuid.parse("6E400002-B5A3-F393-E0A9-E50E24DCCA9E");
Uuid _UART_TX = Uuid.parse("6E400003-B5A3-F393-E0A9-E50E24DCCA9E");
// Uuid _UART_UUID = Uuid.parse("6e400001-b5a3-f393-e0a9-e50e24dcca9e");
// Uuid _UART_RX   = Uuid.parse("6e400002-b5a3-f393-e0a9-e50e24dcca9e");
// Uuid _UART_TX   = Uuid.parse("6e400003-b5a3-f393-e0a9-e50e24dcca9e");

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter_reactive_ble example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter_reactive_ble UART example'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final flutterReactiveBle = FlutterReactiveBle();
  List<DiscoveredDevice> _foundBleUARTDevices = [];
  StreamSubscription<DiscoveredDevice> _scanStream;
  Stream<ConnectionStateUpdate> _currentConnectionStream;
  StreamSubscription<ConnectionStateUpdate> _connection;
  QualifiedCharacteristic _txCharacteristic;
  QualifiedCharacteristic _rxCharacteristic;
  Stream<List<int>> _receivedDataStream;
  TextEditingController _dataToSendText;
  bool _scanning = false;
  bool _connected = false;
  String _logTexts = "";
  List<String> _receivedData = [];
  int _numberOfMessagesReceived = 0;

  void initState() {
    super.initState();
    _dataToSendText = TextEditingController();
    initBle();
  }

  void initBle() async {
    print('starting scan');
    _startScan();

    while (true) {
      if (_foundBleUARTDevices.isNotEmpty) {
        print('stopping scan');
        _stopScan();
        break;
      } else {
        print('waiting 3 sec for start scan to complete');
        await Future.delayed(Duration(seconds: 1), () {});
      }
    }

    while (true) {
      if (!_scanning) {
        print('connecting to module');
        onConnectDevice(0);
        break;
      } else {
        print('waiting  1 sec for Stop scan to complete');
        await Future.delayed(Duration(seconds: 1), () {});
      }
    }

    while (true) {
      if (_connected) {
        break;
      } else {
        print('waiting 1 sec to connect to module');
        await Future.delayed(Duration(seconds: 3), () {});
      }
    }

    print('sending first data packet)');
    _sendData('18EF9697080100F1FFFE010101');
  }

  // void initBle() async {
  //   print('starting scan');
  //   await _startScan();
  //   print('stopping scan');
  //   await _stopScan();
  //   print('connecting to module');
  //   await onConnectDevice(0);
  //
  //   print('sending first data packet)');
  //   _sendData('18EF9697080100F1FFFE010101');
  // }

  void refreshScreen() {
    setState(() {});
  }

  Future<void> _sendUserInputData() async {
    await flutterReactiveBle.writeCharacteristicWithResponse(_rxCharacteristic,
        value: _dataToSendText.text.codeUnits);
  }

  void _sendData(String data) async {
    List<int> value = utf8.encode(data);
    await flutterReactiveBle.writeCharacteristicWithResponse(_rxCharacteristic,
        value: value);
  }

  void onNewReceivedData(List<int> data) {
    print("data = $data");
    for (int i in data) {
      print(i.toRadixString(16));
    }
    _numberOfMessagesReceived += 1;
    _receivedData
        .add("$_numberOfMessagesReceived: ${String.fromCharCodes(data)}");
    if (_receivedData.length > 5) {
      _receivedData.removeAt(0);
    }
    refreshScreen();
  }

  void _disconnect() async {
    await _connection.cancel();
    _connected = false;
    refreshScreen();
  }

  void _stopScan() async {
    await _scanStream.cancel();
    _scanning = false;
    refreshScreen();
  }

  Future<void> showNoPermissionDialog() async => showDialog<void>(
        context: context,
        barrierDismissible: false, // user must tap button!
        builder: (BuildContext context) => AlertDialog(
          title: const Text('No location permission '),
          content: SingleChildScrollView(
            child: ListBody(
              children: <Widget>[
                const Text('No location permission granted.'),
                const Text(
                    'Location permission is required for BLE to function.'),
              ],
            ),
          ),
          actions: <Widget>[
            TextButton(
              child: const Text('Acknowledge'),
              onPressed: () {
                Navigator.of(context).pop();
              },
            ),
          ],
        ),
      );

  void _startScan() async {
    bool goForIt = false;
    PermissionStatus permission;
    if (Platform.isAndroid) {
      permission = await LocationPermissions().requestPermissions();
      if (permission == PermissionStatus.granted) goForIt = true;
    } else if (Platform.isIOS) {
      goForIt = true;
    }

    if (goForIt) {
      //TODO replace True with permission == PermissionStatus.granted is for IOS test
      _foundBleUARTDevices = [];
      _scanning = true;
      refreshScreen();
      _scanStream = flutterReactiveBle
          .scanForDevices(withServices: [_UART_UUID]).listen((device) {
        if (_foundBleUARTDevices.every((element) => element.id != device.id)) {
          print("found $device");
          _foundBleUARTDevices.add(device);
          refreshScreen();
        }
      }, onError: (Object error) {
        _logTexts = "${_logTexts}ERROR while scanning:$error \n";
        refreshScreen();
      });
    } else {
      await showNoPermissionDialog();
    }
  }

  void onConnectDevice(index) async {
    _currentConnectionStream = flutterReactiveBle.connectToAdvertisingDevice(
      id: _foundBleUARTDevices[index].id,
      prescanDuration: Duration(seconds: 1),
      withServices: [_UART_UUID, _UART_RX, _UART_TX],
    );
    _logTexts = "";
    refreshScreen();
    _connection = _currentConnectionStream.listen((event) {
      var id = event.deviceId.toString();
      switch (event.connectionState) {
        case DeviceConnectionState.connecting:
          {
            _logTexts = "${_logTexts}Connecting to $id\n";
            break;
          }
        case DeviceConnectionState.connected:
          {
            _logTexts = "${_logTexts}Connected to $id\n";
            _numberOfMessagesReceived = 0;
            _receivedData = [];
            _txCharacteristic = QualifiedCharacteristic(
                serviceId: _UART_UUID,
                characteristicId: _UART_TX,
                deviceId: event.deviceId);
            _receivedDataStream =
                flutterReactiveBle.subscribeToCharacteristic(_txCharacteristic);
            _receivedDataStream.listen((data) {
              onNewReceivedData(data);
            }, onError: (dynamic error) {
              _logTexts = "${_logTexts}Error:$error$id\n";
            });
            _rxCharacteristic = QualifiedCharacteristic(
                serviceId: _UART_UUID,
                characteristicId: _UART_RX,
                deviceId: event.deviceId);
            _connected = true;

            break;
          }
        case DeviceConnectionState.disconnecting:
          {
            _connected = false;
            _logTexts = "${_logTexts}Disconnecting from $id\n";
            break;
          }
        case DeviceConnectionState.disconnected:
          {
            _logTexts = "${_logTexts}Disconnected from $id\n";
            break;
          }
      }
      refreshScreen();
    });
  }

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: SingleChildScrollView(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: <Widget>[
              const Text("BLE UART Devices found:"),
              Container(
                  margin: const EdgeInsets.all(3.0),
                  decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(10),
                      border: Border.all(color: Colors.blue, width: 2)),
                  height: 100,
                  child: ListView.builder(
                      itemCount: _foundBleUARTDevices.length,
                      itemBuilder: (context, index) => Card(
                              child: ListTile(
                            dense: true,
                            enabled: !((!_connected && _scanning) ||
                                (!_scanning && _connected)),
                            trailing: GestureDetector(
                              behavior: HitTestBehavior.translucent,
                              onTap: () {
                                (!_connected && _scanning) ||
                                        (!_scanning && _connected)
                                    ? () {}
                                    : onConnectDevice(index);
                              },
                              child: Container(
                                width: 48,
                                height: 48,
                                padding:
                                    const EdgeInsets.symmetric(vertical: 4.0),
                                alignment: Alignment.center,
                                child: const Icon(Icons.add_link),
                              ),
                            ),
                            subtitle: Text(_foundBleUARTDevices[index].id),
                            title: Text(
                                "$index: ${_foundBleUARTDevices[index].name}"),
                          )))),
              const Text("Status messages:"),
              Container(
                  margin: const EdgeInsets.all(3.0),
                  width: 1400,
                  decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(10),
                      border: Border.all(color: Colors.blue, width: 2)),
                  height: 90,
                  child: Scrollbar(
                      child: SingleChildScrollView(child: Text(_logTexts)))),
              const Text("Received data:"),
              Container(
                  margin: const EdgeInsets.all(3.0),
                  width: 1400,
                  decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(10),
                      border: Border.all(color: Colors.blue, width: 2)),
                  height: 90,
                  child: Text(_receivedData.join("\n"))),
              const Text("Send message:"),
              Container(
                  margin: const EdgeInsets.all(3.0),
                  padding: const EdgeInsets.all(8.0),
                  decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(10),
                      border: Border.all(color: Colors.blue, width: 2)),
                  child: Row(children: <Widget>[
                    Expanded(
                        child: TextField(
                      enabled: _connected,
                      controller: _dataToSendText,
                      decoration: const InputDecoration(
                          border: InputBorder.none, hintText: 'Enter a string'),
                    )),
                    RaisedButton(
                        child: Icon(
                          Icons.send,
                          color: _connected ? Colors.blue : Colors.grey,
                        ),
                        onPressed: _connected ? _sendUserInputData : () {}),
                  ]))
            ],
          ),
        ),
        persistentFooterButtons: [
          Container(
            height: 35,
            child: Column(
              children: [
                if (_scanning)
                  const Text("Scanning: Scanning")
                else
                  const Text("Scanning: Idle"),
                if (_connected)
                  const Text("Connected")
                else
                  const Text("disconnected."),
              ],
            ),
          ),
          RaisedButton(
            onPressed: !_scanning && !_connected ? _startScan : () {},
            child: Icon(
              Icons.play_arrow,
              color: !_scanning && !_connected ? Colors.blue : Colors.grey,
            ),
          ),
          RaisedButton(
              onPressed: _scanning ? _stopScan : () {},
              child: Icon(
                Icons.stop,
                color: _scanning ? Colors.blue : Colors.grey,
              )),
          RaisedButton(
              onPressed: _connected ? _disconnect : () {},
              child: Icon(
                Icons.cancel,
                color: _connected ? Colors.blue : Colors.grey,
              ))
        ],
      );
}
导入'dart:async';
导入“dart:convert”;
进口“包装:颤振/材料.省道”;
进口“包装:颤振反应式/颤振反应式.省道”;
导入“package:location_permissions/location_permissions.dart”;
导入“dart:io”展示平台;
//此颤振应用程序演示了颤振响应颤振插件的用法
//此应用程序仅适用于使用北欧UART服务(NUS)UUID进行广告的BLE设备
Uuid _UART_Uuid=Uuid.parse(“6E400001-B5A3-F393-E0A9-e50e24dca9e”);
Uuid _UART_RX=Uuid.parse(“6E400002-B5A3-F393-E0A9-e50e24dca9e”);
Uuid _UART_TX=Uuid.parse(“6E400003-B5A3-F393-E0A9-e50e24dca9e”);
//Uuid _UART_Uuid=Uuid.parse(“6e400001-b5a3-f393-e0a9-e50e24dca9e”);
//Uuid _UART_RX=Uuid.parse(“6e400002-b5a3-f393-e0a9-e50e24dca9e”);
//Uuid _UART_TX=Uuid.parse(“6e400003-b5a3-f393-e0a9-e50e24dca9e”);
void main(){
runApp(MyApp());
}
类MyApp扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回材料PP(
标题:“颤振反应示例”,
主题:主题数据(
主样本:颜色。蓝色,
视觉密度:视觉密度。自适应平台密度,
),
主页:MyHomePage(标题:“颤振响应UART示例”),
);
}
}
类MyHomePage扩展StatefulWidget{
MyHomePage({Key,this.title}):超级(Key:Key);
最后的字符串标题;
@凌驾
_MyHomePageState createState()=>\u MyHomePageState();
}
类_MyHomePageState扩展状态{
最终颤振反应性=颤振反应性();
列表_foundbleAutDevices=[];
StreamSubscription\u scanStream;
流-当前连接流;
流订阅连接;
定性特征xCharacteristic;
定性特征rxCharacteristic;
流(接收数据流);;
text编辑控制器(dataToSendText);
布尔扫描=假;
bool _connected=false;
字符串_logtext=“”;
列表_receivedData=[];
int _numberOfMessagesReceived=0;
void initState(){
super.initState();
_dataToSendText=TextEditingController();
initBle();
}
void initBle()异步{
打印(“开始扫描”);
_startScan();
while(true){
if(_foundbleAutDevices.isNotEmpty){
打印(“停止扫描”);
_停止扫描();
打破
}否则{
打印(“等待3秒开始扫描完成”);
等待未来。延迟(持续时间(秒:1),(){});
}
}
while(true){
如果(!\u扫描){
打印(“连接到模块”);
未连接设备(0);
打破
}否则{
打印(“等待1秒停止扫描完成”);
等待未来。延迟(持续时间(秒:1),(){});
}
}
while(true){
如果(_已连接){
打破
}否则{
打印(“等待1秒以连接到模块”);
等待未来。延迟(持续时间(秒:3),({});
}
}
打印(“发送第一个数据包”);
_sendData('18EF96970801000F1FFFE010101');
}
//void initBle()异步{
//打印(“开始扫描”);
//等待_startScan();
//打印(“停止扫描”);
//等待_stopScan();
//打印(“连接到模块”);
//等待连接设备(0);
//
//打印(“发送第一个数据包”);
//_sendData('18EF96970801000F1FFFE010101');
// }
无效刷新屏幕(){
setState((){});
}
Future\u sendUserInputData()异步{
等待颤振可反应。writeCharacteristicWithResponse(\u rxCharacteristic,
值:_dataToSendText.text.codeUnits);
}
void\u sendData(字符串数据)异步{
列表值=utf8.编码(数据);
等待颤振可反应。writeCharacteristicWithResponse(\u rxCharacteristic,
价值:价值);
}
void onnerReceivedData(列表数据){
打印(“数据=$data”);
for(数据中的int i){
印刷品(i.toRadixString(16));
}
_numberOfMessagesReceived+=1;
_收到数据
.add(“$\u numberOfMessagesReceived:${String.fromCharCodes(data)}”);
如果(_receivedData.length>5){
_receivedData.removeAt(0);
}
刷新屏幕();
}
void\u disconnect()异步{
等待连接。取消();
_连接=错误;
刷新屏幕();
}
void\u stopScan()异步{
等待扫描流。取消();
_扫描=假;
刷新屏幕();
}
Future showNoPermissionDialog()异步=>showDialog(
上下文:上下文,
barrierDismissible:false,//用户必须点击按钮!
生成器:(BuildContext上下文)=>AlertDialog(
标题:常量文本(“无位置权限”),
内容:SingleChildScrollView(
子:列表体(
儿童:[
常量文本('未授予位置权限'),
常量文本(
“需要位置权限才能使用BLE。”),
],
),
),
行动:[
文本按钮(
子项:常量文本(“确认”),