【问题标题】:Flutter Best way to Pass data from a class to a widget variableFlutter 将数据从类传递到小部件变量的最佳方法
【发布时间】:2021-08-11 02:06:39
【问题描述】:

我正在使用 Speech_to_text 包 将语音识别结果存储在一个字符串变量中,以后我可以将其用于不同的目的,到目前为止,我只想在屏幕上显示字符串。我想实现类似于 Whatsaap 录制的功能,所以我有 GestureDetectoronLongPress 开始录制和 onLongPressUp 停止它。

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  
  //Variable to show on screen
  String text = 'Press the button and start speaking';
  
  bool isListening = false;

  final SpeechToText speech = SpeechToText();

  String lastError = "";
  String lastStatus = "";
  String _currentLocaleId = "";

  @override
  void initState() {
    super.initState();
    initSpeechState();
  }

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          title: Text(MyApp.title),
          centerTitle: true,
        ),
        body: SingleChildScrollView(
          reverse: true,
          padding: const EdgeInsets.all(30).copyWith(bottom: 150),
          child: SubstringHighlight(
            text: text,
            terms: Command.all,
            textStyle: TextStyle(
              fontSize: 32.0,
              color: Colors.black,
              fontWeight: FontWeight.w400,
            ),
            textStyleHighlight: TextStyle(
              fontSize: 32.0,
              color: Colors.red,
              fontWeight: FontWeight.w400,
            ),
          ),
        ),
        floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
        floatingActionButton: AvatarGlow(
          animate: isListening,
          endRadius: 75,
          glowColor: Theme.of(context).primaryColor,
          child: GestureDetector(
            child: FloatingActionButton(
              child: Icon(isListening ? Icons.mic : Icons.mic_none, size: 36),
              /*onPressed: () {
                toggleRecording();
                print(text);
              }*/
              onPressed: () {},
            ),
            onLongPress: () {
              setState(() async {
                text = await Speech.startListening();
              });

              // print(text);
            },
            onLongPressUp: Speech.stopListening,

            //sendMessage(),
          ),
        ),
      );

  Future<void> initSpeechState() async {
    bool hasSpeech = await speech.initialize(
        onError: errorListener, onStatus: statusListener, debugLogging: false);
  }

  //Speech to text methods
  Future<void> errorListener(SpeechRecognitionError error) async {
    print("Received error status: $error, listening: ${speech.isListening}");
    if (mounted) {
      setState(() {
        lastError = "${error.errorMsg} - ${error.permanent}";
        print(lastError);
      });
    }
  }

  void statusListener(String status) {
    setState(() {
      print(status);
      lastStatus = "$status";
    });
  }
}

OnLongPressOnLongPressUp 分别调用不同类中的方法 startListeningstopListening

class Speech {
  static final _speech = SpeechToText();
  static String lastWords;


  void cancelListening() {
    _speech.cancel();
  }

  static Future startListening() async {
    await _speech.listen(
        onResult: resultListener,
        listenFor: Duration(minutes: 1),
        cancelOnError: true,
        partialResults: false);
    return lastWords;
  }

  static void stopListening() {
    _speech.stop();
    
  }

  static resultListener(SpeechRecognitionResult result) {
    lastWords = "${result.recognizedWords}";
    //print(lastWords);
    if (lastWords != '') {
      //this is what I want to pass to the Text variable on the Main Widget
      print(lastWords);
    }
  }
}

我以为我只需要将 startListening 方法分配给主小部件中的 Text 变量

 onLongPress: () {
              setState(() async {
                text = await Speech.startListening();
              });

鉴于athe 方法正在返回所需的字符串

 static Future startListening() async {
    await _speech.listen(
        onResult: resultListener,
        listenFor: Duration(minutes: 1),
        cancelOnError: true,
        partialResults: false);
    return lastWords;
  }

但这种方法导致了 redScreen 错误:

════════手势捕获的异常 ═════════════════════════════════════════╕下面的断言 在处理手势时被抛出:setState() 回调参数 返回一个 Future。

_HomePageState#0ff8a 上的 setState() 方法被调用 返回 Future 的闭包或方法。也许它被标记为 “异步”。

不是在 setState() 调用中执行异步工作,而是 首先执行工作(不更新小部件状态),然后 在对 setState() 的调用中同步更新状态。

抛出异常时,这是堆栈 #0 状态.setState。包:flutter/…/widgets/framework.dart:1270 #1 State.setState 包:flutter/…/widgets/framework.dart:1286 #2 _HomePageState.build。 lib\page\home_page.dart:75 #3 GestureRecognizer.invokeCallback 包:flutter/…/gestures/recognizer.dart:182 #4 LongPressGestureRecognizer._checkLongPressStart package:flutter/.../gestures/long_press.dart:423 ... 处理程序: “onLongPress”识别器:LongPressGestureRecognizer#ac97b debugOwner:手势检测器 状态:可能══════════════════════════════════════════════════════════ ═════════════════════════════════ I/flutter (11164):聆听

════════ 小部件库捕获的异常 ═══════════════════════════════════方法'toLowerCase'是 调用为空。接收者:null 尝试调用:toLowerCase() 相关的导致错误的小部件是 SubstringHighlight lib\page\home_page.dart:45 ══════════════════════════════════════════════════ ══════════════════════════════

,所以我想我可以使用resultListener,它只在有voicerecognition 结果时被调用,将lastwords 字符串发送到主窗口小部件中的文本变量,但我没有想通了。

P.D. 让主小部件上的所有方法都有效,但我试图实现干净的架构,所以我想将该逻辑与 Ui 小部件分开。

谢谢。

//-------- 更新 -----

我一直在研究,并找到了一种使用流使其工作的方法,

我在 Speech 类中创建了一个流控制器,然后在结果监听器中添加了一个接收器。

static resultListener(SpeechRecognitionResult result) {
    lastWords = "${result.recognizedWords}";
    //print(lastWords);
    if (lastWords != '') {
      streamController.sink.add(lastWords);
    }

在主 Widget 中,我在 OnLongPress 函数中实现了流监听。

  onLongPress: () {
              Speech.startListening();
              Speech.streamController.stream.listen((data) {
                print("recibido: $data");
                setState(() {
                  text = data;
                });
              });

到目前为止,它运行良好,但我不知道这是否是处理此数据传输的最佳方式。如果有人知道更好的方法,我将不胜感激,如果这是一个很好的方法,那就是这个问题的答案。

// .-................ 第二次更新--------

这种方法似乎有效,但我意识到一段时间后我开始多次获得相同的数据

I/flutter (20460): 听 I/flutter (20460): notListening I/flutter (20460):recibido:123 I/chatty (20460): uid=10166(com.example.speech_to_text_example) 1.ui 相同 1 行 2 I/flutter (20460):recibido:123 I/chatty (20460): uid=10166(com.example.speech_to_text_example) 1.ui 相同 1 行 I/flutter (20460):recibido:123

对于这个无关紧要的特定示例,但如果我想将该字符串用于诸如使用网络服务之类的问题,那么我只想在每次开始录制时获取一次。

谢谢。

【问题讨论】:

    标签: flutter dart speech-to-text


    【解决方案1】:

    如果你想同时显示它,我认为你需要在 lastwords 发生变化时通知父类。将您的语音识别类移动到小部件可以成功。在顶部创建一个变量而不是 lastwords 并显示在文本小部件中。

     void startListening() async {
        await _speech.listen(
            onResult: (val) =>
        setState(() {
       _lastwords=val.recognizedWords;
          });
            cancelOnError: true,
            partialResults: false);
       
      }
    

    【讨论】:

    • 嗨@Alperen baskaya,将所有方法移动到主小部件有效,但我想保持 UI 和逻辑分开。
    【解决方案2】:

    我的方法是在将未来分配给 setstate 中的文本之前有一个额外的变量来存储它

    onLongPress: () async  {
       var txt = await Speech.startListening();
       setState(() {
          text = txt;
       });
    }
    

    【讨论】:

    • 我试过了,但我得到了这个错误:════════ 小部件库捕获的异常══════════════════ ═════════════════ 在构建 SubstringHighlight(dirty) 时引发了以下 NoSuchMethodError:在 null 上调用了方法 'toLowerCase'。接收者:null 尝试调用:toLowerCase() 相关的导致错误的小部件是 SubstringHighlight lib\page\home_page.dart:45
    【解决方案3】:

    我之前的解决方案的问题是我使用 StreamController 作为广播,并且每次我使用麦克风按钮时监听器都会创建一个实例,从而导致冗余数据。为了解决这种情况,我在 Speech 类中创建了一个流控制器,然后在结果监听器中添加了一个接收器。

    StreamController<String> streamController = StreamController();
    
    static resultListener(SpeechRecognitionResult result) {
        lastWords = "${result.recognizedWords}";
        //print(lastWords);
        if (lastWords != '') {
          streamController.sink.add(lastWords);
    }
    

    在主 Widget 中,我在 initState 中调用了 streamController 侦听器,因此侦听器仅实例化一次,从而防止出现冗余数据和 “Stream 已被侦听” 错误。

    @override
      void initState() {
        super.initState();
        initSpeechState();    
        speech.streamController.stream.listen((event) {
          setState(() {
            text = event;
            print(text);
          });
     
        });
      }  
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-07-30
      • 2021-10-12
      • 2018-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-11
      相关资源
      最近更新 更多