如何同步来自 dart 中异步函数的调用

How to synchronize a call from the asynchronous function in dart

我正在用 Flutter 开发我的第一个应用程序,我对 Java 和 js 有一些经验,但我以前从未使用过 flutter,如果我的问题对你来说很荒谬,我很抱歉。

该应用程序是语音助手聊天机器人,它应该对客户收到的每条新消息执行文本到语音转换,我的问题是因为我使用的是 firebase 消息传递,所以我收到的所有请求都在异步调用,但我需要同步对文本到语音服务的访问,否则我 运行 会遇到一个文本中断另一个文本的问题。

这是我的代码目前的样子: Firebase 消息传递:

onMessage: (Map<String, dynamic> message) {
        return this.handleBotMessage(appState, message);
},

决定如何处理每个特定消息的方法:

Future handleBotMessage(
    Store<AppState> store,
    Map<String, dynamic> dataJson,
  ) {
      #logic that convert the message into json and extracts the message type

      if (type == MessageType.CHAT_MESSAGE) {
        return handleChatMessage(store, subtype, messageMap);
      }
  }

处理短信的方法:

Future<dynamic> handleChatMessage(
    Store<AppState> store,
    MessageSubtype subtype,
    Map<String, dynamic> message,
  ) {
    #Text to speach is build as a singleton and this always returns the same instance
    TextToSpeech tts = TextToSpeech();
    if (subtype == MessageSubtype.TEXT) {
      TextMessage textMessage = TextMessage.fromJson(message);
      return tts
          .speak(textMessage.text)
          .then((result) => store.dispatch(NewBotMessageAction(textMessage)));
    } else if (subtype == MessageSubtype.QUICK_REPLY) {
      QuickReplyMessage qrMessage = QuickReplyMessage.fromJson(message);
      return tts
          .speak(qrMessage.text)
          .then((result) => store.dispatch(NewQrOptionsAction(qrMessage)));
    } else {
      throw new Exception('Unexpected message subtype!');
    }
  }

实际执行文字转语音的方法

Future<dynamic> speak(String text) async {
    return flutterTts.speak(text).then((resp) {
      ttsRunning = false;
      print(resp);
      return resp;
    }, onError: (obj, st) {
      ttsRunning = false;
      print(obj);
      print(st.toString());
    });
  }

文字转语音初始化

Future init() async {
    await flutterTts.setLanguage("en-US");
    var res = await flutterTts.isLanguageAvailable("en-US");
    print(res);
    return res;
  }

https://pub.dev/packages/flutter_tts

如果您不希望新消息打断正在说话的消息,您可以将它们排队。这样,新消息将等待当前消息完成。看看这个方法:

Queue of Future in dart

好的,我找到了解决方案,问题正如 frank06 指出的那样,flutter tts 会立即完成未来,而不是在说出整个短语之后。
所以这是我的解决方案,它并不完美,但它有效:

Completer completer;
Future<dynamic> speak(String text) {
    print('Started speeking');
    print(new DateTime.now().toIso8601String());
    if (TextToSpeech.lastRequest == null) {
      lastRequest = _executeSpeech(text);
    } else {
      lastRequest = lastRequest.then((resp) {
        return _executeSpeech(text);
      });
    }
    return lastRequest;
  }

  Future<dynamic> _executeSpeech(String text) {
    completer = Completer();
    flutterTts.speak(text).then((resp) {
      ttsRunning = false;
      print(resp);
      return resp;
    }, onError: (obj, st) {
      ttsRunning = false;
      print(obj);
      print(st.toString());
    });
    return completer.future;
  }


flutterTts.setCompletionHandler(() {
  print('Finished speeking');
  print(new DateTime.now().toIso8601String());
  ttsState = TtsState.stopped;
  completer.complete(ttsState);
});

flutterTts.setErrorHandler((msg) {
  ttsState = TtsState.stopped;
  completer.complete(ttsState);
});