You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何查询TextToSpeech队列已处理的语音合成条目数量

解决TextToSpeech中途停止后定位已处理条目的问题

嘿Mike,我完全懂你的困扰——当你用循环把ArrayList里的内容批量加入TTS队列后,中途点击停止却没法准确知道它已经读完了第几条,没法对应到原列表的位置,对吧?

其实Android的TextToSpeech本身并没有直接提供查询队列已完成条目数的API,但我们可以通过UtteranceProgressListener来自己跟踪每个朗读任务的完成状态,这样就能精准记录已处理的条目数量了。

具体实现步骤:

  1. 给TextToSpeech设置进度监听器
    这个监听器可以监听每个朗读任务的开始、完成和错误状态,我们在里面维护一个计数器,每完成一条就递增计数。

    // 初始化TextToSpeech时设置监听器
    textToSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() {
        private int completedUtterances = 0;
    
        @Override
        public void onStart(String utteranceId) {
            // 可选:任务开始时的逻辑,比如高亮当前朗读条目
        }
    
        @Override
        public void onDone(String utteranceId) {
            // 每完成一条,计数器+1
            completedUtterances++;
        }
    
        @Override
        public void onError(String utteranceId) {
            // 即使出错,也标记为已处理,避免计数错位
            completedUtterances++;
        }
    
        // 提供获取已完成计数的方法
        public int getCompletedCount() {
            return completedUtterances;
        }
    
        // 重置计数器,每次开始新的朗读任务前调用
        public void resetCount() {
            completedUtterances = 0;
        }
    });
    
  2. 给每个朗读任务添加唯一标识
    在调用speak()方法时,需要给每个任务设置一个utteranceId,这样监听器能准确识别每个任务的完成状态(虽然这里我们主要用计数器,但标识是监听器工作的必要条件)。

    修改你的speech方法:

    private void speech(String text) {
        HashMap<String, String> utteranceParams = new HashMap<>();
        // 用当前章节数作为唯一标识,和你的CurChapter对应
        utteranceParams.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, String.valueOf(sh.CurChapter));
        textToSpeech.speak(text, TextToSpeech.QUEUE_ADD, utteranceParams);
    }
    
  3. 开始朗读前重置计数器
    在你的循环开始前,先把计数器清零,避免上次朗读的计数影响:

    if(!sh.Contents.isEmpty()) { 
        // 重置计数器
        ((UtteranceProgressListener)textToSpeech.getOnUtteranceProgressListener()).resetCount();
        sh.CurChapter = 0; // 记得把CurChapter重置为0,避免累加之前的数值
        for (String object: sh.Contents) { 
            sh.CurChapter += 1; 
            speech(String.valueOf(sh.CurChapter) + " " + object); 
        } 
    } else { 
        speech( "Section not found!"); 
    }
    
  4. 点击STOP按钮时获取已处理条目数
    当你点击停止按钮时,先调用textToSpeech.stop()终止当前朗读,然后通过监听器的getCompletedCount()拿到已完成的条目数,就能对应到ArrayList的位置了(注意:因为你的CurChapter从1开始计数,所以列表索引是completedCount - 1)。

    stopButton.setOnClickListener(v -> {
        textToSpeech.stop();
        UtteranceProgressListener listener = (UtteranceProgressListener) textToSpeech.getOnUtteranceProgressListener();
        int processedCount = listener.getCompletedCount();
        
        // 检查计数是否在列表范围内
        if (processedCount > 0 && processedCount <= sh.Contents.size()) {
            // 获取对应的列表条目
            String targetItem = sh.Contents.get(processedCount - 1);
            // 在这里对这个条目进行你需要的操作
            Log.d("TTS", "已处理到第" + processedCount + "条,内容:" + targetItem);
        }
    });
    

注意事项:

  • 确保UtteranceProgressListener的实现是同一个实例,这样计数器才会保持正确状态。
  • 如果你的TTS引擎不支持KEY_PARAM_UTTERANCE_ID(Android API 21+推荐用Bundle),可以替换成以下写法:
    Bundle params = new Bundle();
    params.putString(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, String.valueOf(sh.CurChapter));
    textToSpeech.speak(text, TextToSpeech.QUEUE_ADD, params, null);
    

这样就能完美解决你中途停止后定位已处理条目的问题啦!

内容的提问来源于stack exchange,提问作者Mike Dole

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:42:58