颤振通过蓝牙以暂停模式从ESP32接收数据

时间:2019-12-18 15:05:34

标签: flutter dart

我正在将传感器值从ESP32通过BLE发送到我的Flutter App。当我尝试使用WidgetsBindingObserver实现Background Function时,即使我正在在Instagram上,我收到一条错误消息:


════════ Exception caught by widgets library ═══════════════════════════════════
The following assertion was thrown building StreamBuilder<List<int>>(dirty, state: _StreamBuilderBaseState<List<int>, AsyncSnapshot<List<int>>>#04822):
setState() or markNeedsBuild() called during build.

This SensorPage widget cannot be marked as needing to build because the framework is already in the process of building widgets.  A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was: SensorPage
    state: _SensorPageState#d97dd
The widget which was currently being built when the offending call was made was: StreamBuilder<List<int>>
    dirty
    state: _StreamBuilderBaseState<List<int>, AsyncSnapshot<List<int>>>#04822
The relevant error-causing widget was
    StreamBuilder<List<int>> 
package:flutter_blue_app_2/werte.dart:201
When the exception was thrown, this was the stack
#0      Element.markNeedsBuild.<anonymous closure> 
package:flutter/…/widgets/framework.dart:3896
#1      Element.markNeedsBuild 
package:flutter/…/widgets/framework.dart:3911
#2      State.setState 
package:flutter/…/widgets/framework.dart:1168
#3      _SensorPageState.build.<anonymous closure> 
package:flutter_blue_app_2/werte.dart:210
#4      StreamBuilder.build 
package:flutter/…/widgets/async.dart:425
...
════════════════════════════════════════════════════════════════════════════════

我的代码如下:

import 'dart:async';
import 'dart:convert' show utf8;
import 'dart:io';

import 'package:audioplayers/audio_cache.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:audioplayers/audioplayers.dart';

class SensorPage extends StatefulWidget {
  const SensorPage({Key key, this.device}) : super(key: key);
  final BluetoothDevice device;

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

class _SensorPageState extends State<SensorPage> with WidgetsBindingObserver {
  final String SERVICE_UUID = "4fafc201-1fb5-459e-8fcc-c5c9c331914b";
  final String CHARACTERISTIC_UUID = "beb5483e-36e1-4688-b7f5-ea07361b26a8";

  bool isReady;

  var extrem = 0;
  var val1 = "";
  var pot1 = 0;
  var val2 = "";
  var pot2 = 0;
  var x = 0;

  Stream<List<int>> stream;

  String localFilePath;

  AudioPlayer advancedPlayer;
  AudioCache audioCache;

  AppLifecycleState _notification;

  void backgroundCompute() {
    print('Background Compute Callback');
    print('Receiving Sensor Values');
    sleep(Duration(milliseconds: 200));
    setState(() {});
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    setState(() {
      _notification = state;
    });
  }

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    isReady = false;
    initPlayer();
    connectToDevice();
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  bool _isVisible = true;

  void showToast() {
    setState(() {
      _isVisible = !_isVisible;
    });
  }

  void initPlayer() {
    advancedPlayer = new AudioPlayer();
    audioCache = new AudioCache(fixedPlayer: advancedPlayer);
  }

  connectToDevice() async {
    if (widget.device == null) {
      _Pop();
      return;
    }

    new Timer(
      const Duration(seconds: 15),
      () {
        if (!isReady) {
          disconnectFromDevice();
          _Pop();
        }
      },
    );

    await widget.device.connect();
    discoverServices();
  }

  disconnectFromDevice() {
    if (widget.device == null) {
      _Pop();
      return;
    }

    widget.device.disconnect();
  }

  discoverServices() async {
    if (widget.device == null) {
      _Pop();
      return;
    }

    List<BluetoothService> services = await widget.device.discoverServices();
    services.forEach((service) {
      if (service.uuid.toString() == SERVICE_UUID) {
        service.characteristics.forEach((characteristic) {
          if (characteristic.uuid.toString() == CHARACTERISTIC_UUID) {
            characteristic.setNotifyValue(!characteristic.isNotifying);
            stream = characteristic.value;

            setState(() {
              isReady = true;
            });
          }
        });
      }
    });

    if (!isReady) {
      _Pop();
    }
  }

  Future<bool> _onWillPop() {
    return showDialog(
        context: context,
        builder: (context) =>
            new AlertDialog(
              title: Text(
                "ARE YOU SURE?",
                style: TextStyle(fontSize: 18, fontFamily: "Montserrat"),
              ),
              content: Text(
                "DO YOU WANT TO DISCONNECT DEVICE AND GO BACK?",
                style: TextStyle(fontSize: 18, fontFamily: "Montserrat"),
              ),
              actions: <Widget>[
                new FlatButton(
                  onPressed: () => Navigator.of(context).pop(false),
                  child: new Text(
                    "NO",
                    style: TextStyle(fontSize: 14, fontFamily: "Montserrat"),
                  ),
                ),
                new FlatButton(
                  onPressed: () {
                    disconnectFromDevice();
                    Navigator.of(context).pop(true);
                  },
                  child: new Text(
                    "YES",
                    style: TextStyle(fontSize: 14, fontFamily: "Montserrat"),
                  ),
                ),
              ],
            ) ??
            false);
  }

  _Pop() {
    Navigator.of(context).pop(true);
  }

  String _dataParser(List<int> dataFromDevice) {
    return utf8.decode(dataFromDevice);
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: _onWillPop,
      child: Scaffold(
        appBar: AppBar(
          backgroundColor: Colors.red[800],
          title: Text(
            "T(RAIN)-SHIRT",
            style: TextStyle(fontWeight: FontWeight.bold, fontSize: 24),
          ),
        ),
        body: Container(
          child: !isReady
              ? Center(
                  child: CircularProgressIndicator(),
                )
              : Container(
                  child: StreamBuilder<List<int>>(
                    stream: stream,
                    builder: (BuildContext context,
                        AsyncSnapshot<List<int>> snapshot) {
                      if (snapshot.hasError)
                        return Text("Error: ${snapshot.error}");
                      if (snapshot.connectionState == ConnectionState.active) {
                        if (_notification == AppLifecycleState.paused) {
                          //backgroundCompute();
                          setState(() {});
                        }
                        if (x > 0) {
                          var currentValue = _dataParser(snapshot.data);
                          val1 = currentValue.split(',')[0];
                          pot1 = int.parse(val1);
                          val2 = currentValue.split(',')[1];
                          pot2 = int.parse(val2);
                        }
                        if (pot1 >= 1500) {
                          audioCache.play("audio.mp4");
                          advancedPlayer.setVolume(1.0);
                          extrem++;
                        } else {
                          advancedPlayer.stop();
                        }
                        return Center(
                          child: Visibility(
                            visible: _isVisible,
                            child: Column(
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                              children: <Widget>[
                                Text(
                                  "$extrem",
                                  style: TextStyle(
                                      color: Colors.black,
                                      fontSize: 30,
                                      fontWeight: FontWeight.bold,
                                      fontFamily: "Montserrat"),
                                ),
                                RaisedButton(
                                  child: Text(
                                    "START",
                                    style: TextStyle(
                                        color: Colors.white,
                                        fontSize: 15,
                                        fontWeight: FontWeight.bold,
                                        fontFamily: "Montserrat"),
                                  ),
                                  onPressed: () {
                                    showToast();
                                    x++;
                                    extrem = 0;
                                  },
                                  color: Colors.red[800],
                                ),
                              ],
                            ),
                            replacement: Column(
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                              children: <Widget>[
                                Text(
                                  "$pot1",
                                  style: TextStyle(
                                      fontSize: 30,
                                      fontWeight: FontWeight.bold,
                                      fontFamily: "Montserrat"),
                                ),
                                Text(
                                  "$pot2",
                                  style: TextStyle(
                                      fontSize: 30,
                                      fontWeight: FontWeight.bold,
                                      fontFamily: "Montserrat"),
                                ),
                                RaisedButton(
                                  child: Text(
                                    "STOP",
                                    style: TextStyle(
                                        color: Colors.white,
                                        fontSize: 15,
                                        fontWeight: FontWeight.bold,
                                        fontFamily: "Montserrat"),
                                  ),
                                  onPressed: () {
                                    showToast();
                                    x = 0;
                                    pot1 = 0;
                                    pot2 = 0;
                                  },
                                  color: Colors.red[800],
                                ),
                              ],
                            ),
                          ),
                        );
                      } else {
                        return Text("CHECK THE STREAM");
                      }
                    },
                  ),
                ),
        ),
        backgroundColor: Colors.grey[300],
      ),
    );
  }
}

setState()函数引起了此问题。我在后台执行背后的想法是,如果AppLifeCycleState被暂停,则执行setState()再次启动Widget build(Build context),并在App仍暂停的情况下通过BLE从ESP32获取值。谬论? 感谢我得到的每一个帮助。

0 个答案:

没有答案