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

Android中如何像媒体播放器一样,无需合成音频即可暂停恢复Google TTS?

嘿,这个问题我之前帮不少开发者捋清楚过——Google TTS本身确实没有原生的暂停/恢复接口,但咱们完全可以不用提前合成音频,通过分段朗读+状态追踪的方式来实现类似媒体播放器的控制效果。下面是具体的实现思路和代码示例:

核心思路

把需要朗读的长文本拆分成短小的逻辑片段(比如句子、短语),然后逐个播放这些片段。同时我们追踪当前播放到哪个片段、以及是否处于暂停状态:

  • 点击暂停时,停止当前正在播放的片段,标记暂停状态
  • 点击恢复时,从当前暂停的片段继续往后播放
具体实现步骤

1. 初始化TextToSpeech并设置播放监听器

首先要初始化TextToSpeech,并且通过UtteranceProgressListener监听每个片段的播放完成事件,这样我们才能自动触发下一个片段的播放。每个片段需要设置唯一的utterance ID,方便我们追踪播放进度。

private lateinit var tts: TextToSpeech
private var currentSegmentIndex = 0
private var isPaused = false
private var textSegments: List<String> = emptyList()

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // 初始化TTS引擎
    tts = TextToSpeech(this) { status ->
        if (status == TextToSpeech.SUCCESS) {
            // 设置目标语言,这里以中文为例
            val langResult = tts.setLanguage(Locale.CHINESE)
            if (langResult == TextToSpeech.LANG_MISSING_DATA || langResult == TextToSpeech.LANG_NOT_SUPPORTED) {
                Log.e("TTS", "当前设备不支持目标语言")
            }
            // 设置 utterance 进度监听器,追踪每个片段的播放状态
            tts.setOnUtteranceProgressListener(object : UtteranceProgressListener() {
                override fun onStart(utteranceId: String?) {
                    // 可选:更新UI,比如显示"正在播放"状态
                }

                override fun onDone(utteranceId: String?) {
                    // 当前片段播放完成,自动播放下一个(如果未暂停)
                    runOnUiThread {
                        if (!isPaused && currentSegmentIndex < textSegments.size - 1) {
                            currentSegmentIndex++
                            playCurrentSegment()
                        }
                    }
                }

                override fun onError(utteranceId: String?) {
                    Log.e("TTS", "片段播放出错: $utteranceId")
                }
            })
        } else {
            Log.e("TTS", "TTS引擎初始化失败")
        }
    }
}

2. 拆分文本为可播放的小片段

把长文本拆分成短小的片段,这样暂停和恢复的响应会更及时。你可以根据文本类型(中文/英文)调整分割规则,比如按标点、换行符分割:

private fun splitTextIntoSegments(text: String): List<String> {
    // 针对中文文本的分割规则:按常用标点和换行分割
    val splitRegex = Regex("[。!?.!?\\n]")
    return text.split(splitRegex)
        .filter { it.isNotBlank() } // 过滤空字符串
        .map { it.trim() } // 去除前后空格
}

3. 实现播放、暂停、恢复的核心逻辑

  • 开始播放:初始化片段列表,重置播放索引,启动第一个片段的朗读
  • 暂停播放:停止当前TTS播放,标记暂停状态
  • 恢复播放:取消暂停标记,继续播放当前索引的片段
// 对外暴露的开始朗读方法
fun startSpeaking(text: String) {
    textSegments = splitTextIntoSegments(text)
    currentSegmentIndex = 0
    isPaused = false
    playCurrentSegment()
}

// 播放当前索引对应的片段
private fun playCurrentSegment() {
    if (currentSegmentIndex >= textSegments.size) return
    val currentText = textSegments[currentSegmentIndex]
    // 设置唯一的utterance ID,用当前索引作为标识
    val ttsParams = HashMap<String, String>()
    ttsParams[TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID] = currentSegmentIndex.toString()
    // 朗读当前片段,清空之前的播放队列
    tts.speak(currentText, TextToSpeech.QUEUE_FLUSH, ttsParams, null)
}

// 暂停朗读
fun pauseSpeaking() {
    if (tts.isSpeaking) {
        tts.stop()
        isPaused = true
    }
}

// 恢复朗读
fun resumeSpeaking() {
    if (isPaused) {
        isPaused = false
        playCurrentSegment()
    }
}

4. 收尾工作:释放TTS资源

记得在页面销毁时释放TTS引擎资源,避免内存泄漏:

override fun onDestroy() {
    super.onDestroy()
    tts.stop()
    tts.shutdown()
}
额外提示
  • 如果是英文文本,可以调整分割规则(比如按空格、逗号分割),让片段更短,暂停响应更灵敏
  • 这种方式的唯一小局限是无法精准暂停到单词/字符中间,但对于大多数场景已经足够满足需求了

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:27:27