TTS播放暂停功能开发求助:停止语音后循环无法终止
解决TTS播放暂停与循环终止问题
我看了你遇到的问题:想给TTS加暂停/播放功能,但暂停时循环停不下来,也没法准确获取最后播放的词汇。核心问题在于你的同步循环+异步TTS调用的矛盾,还有没正确用标志位中断循环。咱们一步步来修复:
问题分析
- 同步循环阻塞,无法响应暂停:
speakSpeech里的while循环是同步执行的,哪怕你设置了keepGoing=false,循环还是会把所有词汇都塞进TTS队列,根本停不下来——因为循环没在每次迭代时检查这个标志。 - TTS异步调用无法跟踪播放位置:你一次性把所有词汇都加入播放队列,没法知道当前正在播放哪一个,暂停时自然没法准确记录最后播放的位置。
- 暂停逻辑冗余:
toggleAudioMode里调用speakSpeech(0, "stop")完全没必要,直接停止TTS就行,而且这个调用里的循环还会多跑一遍。
修复方案
我们需要改成逐个播放词汇,用TTS的UtteranceProgressListener监听每个词汇的播放完成事件,同时在播放流程中检查keepGoing标志,这样就能随时中断播放,也能准确记录当前位置。
修改后的完整代码示例
private TextToSpeech textToSpeech; private boolean isPlayerVisible = false; private boolean keepGoing = true; private String[] splitspeech; private int currentIndex = 0; // 记录当前播放的词汇索引 private HashMap<String, String> myHash = new HashMap<>(); public void initTTS() { // 初始化TTS时设置监听器 textToSpeech = new TextToSpeech(context, status -> { if (status == TextToSpeech.SUCCESS) { // 设置语言等初始化操作... // 添加Utterance监听器,跟踪每个词汇的播放完成 textToSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() { @Override public void onStart(String utteranceId) {} @Override public void onDone(String utteranceId) { // 当前词汇播放完成,继续播放下一个(如果keepGoing为true) if (keepGoing && currentIndex < splitspeech.length - 1) { currentIndex++; speakNextWord(); } } @Override public void onError(String utteranceId) {} }); } }); } public void toggleAudioMode() { isPlayerVisible = !isPlayerVisible; ivToggleAudioModeAnswer.setImageResource(isPlayerVisible ? R.drawable.ic_audio_off : R.drawable.ic_audio_on); if (isPlayerVisible) { // 开始/继续播放 keepGoing = true; if (splitspeech == null) { splitspeech = result.split(" "); } speakNextWord(); } else { // 暂停播放 keepGoing = false; textToSpeech.stop(); // 这里currentIndex就是最后播放到的词汇索引 } } private void speakNextWord() { if (!keepGoing || currentIndex >= splitspeech.length) { return; } myHash.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "utterance_" + currentIndex); // 每次播放单个词汇,用QUEUE_FLUSH清空之前的队列(避免暂停后残留) textToSpeech.speak(splitspeech[currentIndex].trim(), TextToSpeech.QUEUE_FLUSH, myHash); } // 别忘了在Activity/Fragment销毁时释放TTS @Override protected void onDestroy() { if (textToSpeech != null) { textToSpeech.stop(); textToSpeech.shutdown(); } super.onDestroy(); }
关键修改点解释
- UtteranceProgressListener:监听每个词汇的播放完成事件,确保播放完一个再播下一个,这样我们能精准控制播放流程。
- currentIndex变量:代替原来的
i和j,统一记录当前播放到的词汇索引,暂停时直接保存这个值,继续播放时从这里开始。 - keepGoing标志位:在
speakNextWord和监听器的onDone方法里都检查这个标志,一旦设置为false,就停止继续播放下一个词汇。 - 暂停逻辑简化:暂停时直接调用
textToSpeech.stop()停止当前播放,同时记录currentIndex,不需要再调用冗余的speakSpeech方法。
这样修改后,你就能实现正常的播放/暂停功能,暂停时循环会被中断,也能准确获取最后播放的词汇索引啦。
内容的提问来源于stack exchange,提问作者Sudhir




