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

Android使用ExoPlayer播放视频时TextToSpeech不朗读首个视频名称问题求助

问题根因

TextToSpeech的初始化是异步操作,你在onCreate中初始化TTS之后立刻调用朗读第一个视频名称的逻辑时,onInit回调还没执行完成,TTS实例还没处于就绪状态,所以第一次朗读请求直接被丢弃了。后续视频朗读时TTS已经初始化完成,所以可以正常执行。

解决方案

1. 新增全局变量存储状态和待朗读内容

var tts: TextToSpeech? = null
// 新增两个变量
private var isTtsReady = false
private var pendingSpeakContent: String? = null

2. 修改onInit回调

初始化成功后标记就绪状态,同时检查是否有待朗读的内容,有就直接执行朗读:

override fun onInit(status: Int) {
    val myLanguage = Locale.getDefault().displayLanguage
    if (androidAPILevel < 21) {
        val params: HashMap<String, String> = HashMap()
        params[TextToSpeech.Engine.KEY_PARAM_VOLUME] = musicVolume.toString()
    } else {
        val params = Bundle()
        params.putFloat(
            TextToSpeech.Engine.KEY_PARAM_VOLUME, musicVolume.toFloat()
        )
    }

    if (status == TextToSpeech.SUCCESS) {
        val result = tts!!.setLanguage(Locale.FRENCH)
        if (result == TextToSpeech.LANG_MISSING_DATA
            || result == TextToSpeech.LANG_NOT_SUPPORTED) {
            Log.e("TTS", "*************** 该语言不受支持 ***************")
            speakOut("French not supported, install it please")
            showTheToast(getString(R.string.NoJapaneseLanguage))
        } else {
            tts!!.setSpeechRate(1.0f)
            // 新增逻辑:标记TTS就绪,读取待朗读内容
            isTtsReady = true
            pendingSpeakContent?.let { content ->
                speakOut(content)
                pendingSpeakContent = null
            }
        }
    } else {
        showTheToast("TextToSpeech初始化失败!")
    }
}

3. 改造speakOut方法适配未就绪场景

private fun speakOut(content: String) {
    tts ?: return
    // TTS未就绪时先缓存内容,等初始化完成后再读
    if (!isTtsReady) {
        pendingSpeakContent = content
        return
    }
    // 原有朗读逻辑,注意适配不同API版本
    if (androidAPILevel < 21) {
        val params: HashMap<String, String> = HashMap()
        params[TextToSpeech.Engine.KEY_PARAM_VOLUME] = musicVolume.toString()
        tts!!.speak(content, TextToSpeech.QUEUE_ADD, params)
    } else {
        val params = Bundle()
        params.putFloat(
            TextToSpeech.Engine.KEY_PARAM_VOLUME, musicVolume.toFloat()
        )
        tts!!.speak(content, TextToSpeech.QUEUE_ADD, params, null)
    }
}

4. 补充资源释放逻辑

避免Activity销毁时出现内存泄漏:

override fun onDestroy() {
    tts?.stop()
    tts?.shutdown()
    super.onDestroy()
}

改造完成后直接调用speakOut方法传入视频名称即可,不需要额外判断TTS状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 06:18:03