Discuz! BBS

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 223|回复: 3

TTS Programme

[复制链接]

393

主题

556

帖子

3294

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3294
发表于 2025-9-18 15:43:47 | 显示全部楼层 |阅读模式
在class MainActivity中,private lateinit var tts: TtsHelper
报错:Property must be initialized or be abstract

这个错误是因为你在声明 tts 属性时使用了 lateinit,但没有在构造函数或属性声明时初始化它,而是在 onCreate 方法中初始化。对于 lateinit 属性,Kotlin 要求在使用前必须初始化。

问题分析
lateinit 修饰的属性必须在使用前初始化
你在 onCreate 方法中初始化 tts 属性,但在 setContent 中已经尝试使用了 tts
这导致在 tts 初始化前就尝试使用它

解决方案
方案一:调整代码顺序(推荐)
将 tts 的初始化移到 setContent 之前
  1. class MainActivity : ComponentActivity() {
  2.     private lateinit var tts: TtsHelper
  3.    
  4.     override fun onCreate(savedInstanceState: Bundle?) {
  5.         super.onCreate(savedInstanceState)
  6.         
  7.         // 先初始化 TTS
  8.         tts = TtsHelper(this)
  9.         
  10.         setContent {
  11.             MyTtsTestTheme {
  12.                 // A surface container using the 'background' color from the theme
  13.                 Surface(
  14.                     modifier = Modifier.fillMaxSize(),
  15.                     color = MaterialTheme.colorScheme.background
  16.                 ) {
  17.                     Greeting("Android")
  18.                 }
  19.             }
  20.         }
  21.         
  22.         // 然后使用 TTS
  23.         tts.speak("你好, 世界!")
  24.     }
  25.    
  26.     override fun onDestroy() {
  27.         super.onDestroy()
  28.         tts.shutdown()
  29.     }
  30. }
复制代码


方案二:使用可空类型
将属性声明为可空类型,避免使用 lateinit:
  1. class MainActivity : ComponentActivity() {
  2.     private var tts: TtsHelper? = null
  3.    
  4.     override fun onCreate(savedInstanceState: Bundle?) {
  5.         super.onCreate(savedInstanceState)
  6.         
  7.         setContent {
  8.             MyTtsTestTheme {
  9.                 Surface(
  10.                     modifier = Modifier.fillMaxSize(),
  11.                     color = MaterialTheme.colorScheme.background
  12.                 ) {
  13.                     Greeting("Android")
  14.                 }
  15.             }
  16.         }
  17.         
  18.         tts = TtsHelper(this)
  19.         tts?.speak("你好, 世界!")
  20.     }
  21.    
  22.     override fun onDestroy() {
  23.         super.onDestroy()
  24.         tts?.shutdown()
  25.     }
  26. }
复制代码


方案三:延迟调用 speak 方法
如果需要在 Composable 中使用 TTS,可以将 speak 调用移到点击事件或其他用户交互中:
  1. class MainActivity : ComponentActivity() {
  2.     private lateinit var tts: TtsHelper
  3.    
  4.     override fun onCreate(savedInstanceState: Bundle?) {
  5.         super.onCreate(savedInstanceState)
  6.         
  7.         tts = TtsHelper(this)
  8.         
  9.         setContent {
  10.             MyTtsTestTheme {
  11.                 Surface(
  12.                     modifier = Modifier.fillMaxSize(),
  13.                     color = MaterialTheme.colorScheme.background
  14.                 ) {
  15.                     Greeting("Android") {
  16.                         // 在用户交互时调用
  17.                         tts.speak("你好, 世界!")
  18.                     }
  19.                 }
  20.             }
  21.         }
  22.     }
  23.    
  24.     override fun onDestroy() {
  25.         super.onDestroy()
  26.         tts.shutdown()
  27.     }
  28. }

  29. @Composable
  30. fun Greeting(name: String, onSpeakClick: () -> Unit, modifier: Modifier = Modifier) {
  31.     Column {
  32.         Text(
  33.             text = "Hello $name!",
  34.             modifier = modifier
  35.         )
  36.         Button(onClick = onSpeakClick) {
  37.             Text("说话")
  38.         }
  39.     }
  40. }
复制代码


推荐使用方案一
这是最简单直接的解决方案,只需调整代码顺序即可解决问题
回复

使用道具 举报

393

主题

556

帖子

3294

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3294
 楼主| 发表于 2025-9-18 16:06:31 | 显示全部楼层
遇到的第二个问题:
初始化成功之后,报初始化不完全,就应用tts来Speak了,因此报错:
TextToSpeech            cn.unicoder.myttstest                W  speak failed: TTS engine connection not fully set up

这个警告信息与之前的问题类似,是因为 TTS 引擎连接尚未完全建立就尝试调用 speak 方法。我们需要在 TTS 完全初始化后再调用 speak 方法。

问题分析
TTS 引擎初始化是异步过程
你在初始化完成前就调用了 speak 方法
即使加了 try-catch,仍然会有警告信息

解决方案

修改 TtsHelper.java 文件,添加初始化状态检查和回调机制
  1. package cn.unicoder.myttstest;

  2. import android.content.Context;
  3. import android.speech.tts.TextToSpeech;
  4. import android.util.Log;
  5. import java.util.Locale;

  6. public class TtsHelper {
  7.     private TextToSpeech mTTS;
  8.     private boolean isInitialized = false;

  9.     public TtsHelper(Context context) {
  10.         mTTS = new TextToSpeech(context, new TextToSpeech.OnInitListener() {
  11.             @Override
  12.             public void onInit(int status) {
  13.                 if (status == TextToSpeech.SUCCESS) {
  14.                     // TTS engine is successfully initialized.
  15.                     Log.d("TTS", "初始化成功");
  16.                     isInitialized = true;
  17.                     // 设置语言为中文
  18.                     int result = mTTS.setLanguage(Locale.CHINESE);
  19.                     if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
  20.                         Log.e("TTS", "不支持中文语言");
  21.                         isInitialized = false;
  22.                     }
  23.                 } else {
  24.                     // Failed to initialize TTS engine.
  25.                     Log.e("TTS", "初始化失败,状态码: " + status);
  26.                     isInitialized = false;
  27.                 }
  28.             }
  29.         });
  30.     }
  31.    
  32.     // 添加语音合成方法
  33.     public void speak(String text) {
  34.         if (mTTS != null && isInitialized) {
  35.             try {
  36.                 mTTS.speak(text, TextToSpeech.QUEUE_FLUSH, null, null);
  37.             } catch (Exception e) {
  38.                 Log.e("TTS", "语音合成失败: " + e.getMessage());
  39.             }
  40.         } else {
  41.             Log.w("TTS", "TTS 尚未初始化完成,无法播放: " + text);
  42.         }
  43.     }
  44.    
  45.     // 添加带回调的语音合成方法
  46.     public void speakWhenReady(String text) {
  47.         if (isInitialized) {
  48.             speak(text);
  49.         } else {
  50.             // 如果尚未初始化完成,等待初始化后再播放
  51.             Thread waitThread = new Thread(() -> {
  52.                 int attempts = 0;
  53.                 while (!isInitialized && attempts < 50) { // 最多等待5秒
  54.                     try {
  55.                         Thread.sleep(100);
  56.                         attempts++;
  57.                     } catch (InterruptedException e) {
  58.                         Thread.currentThread().interrupt();
  59.                         return;
  60.                     }
  61.                 }
  62.                 if (isInitialized) {
  63.                     speak(text);
  64.                 } else {
  65.                     Log.e("TTS", "TTS 初始化超时");
  66.                 }
  67.             });
  68.             waitThread.start();
  69.         }
  70.     }
  71.    
  72.     public void shutdown() {
  73.         isInitialized = false;
  74.         if (mTTS != null) {
  75.             mTTS.stop();
  76.             mTTS.shutdown();
  77.         }
  78.     }
  79.    
  80.     // 检查是否已初始化
  81.     public boolean isReady() {
  82.         return isInitialized;
  83.     }
  84. }
复制代码


同时修改 MainActivity.kt 文件:
  1. package cn.unicoder.myttstest

  2. import android.os.Bundle
  3. import androidx.activity.ComponentActivity
  4. import androidx.activity.compose.setContent
  5. import androidx.compose.foundation.layout.Column
  6. import androidx.compose.foundation.layout.fillMaxSize
  7. import androidx.compose.material3.Button
  8. import androidx.compose.material3.MaterialTheme
  9. import androidx.compose.material3.Surface
  10. import androidx.compose.material3.Text
  11. import androidx.compose.runtime.Composable
  12. import androidx.compose.ui.Modifier
  13. import androidx.compose.ui.tooling.preview.Preview
  14. import cn.unicoder.myttstest.ui.theme.MyTtsTestTheme

  15. class MainActivity : ComponentActivity() {
  16.     private var tts: TtsHelper? = null
  17.    
  18.     override fun onCreate(savedInstanceState: Bundle?) {
  19.         super.onCreate(savedInstanceState)
  20.         tts = TtsHelper(this)
  21.         
  22.         setContent {
  23.             MyTtsTestTheme {
  24.                 Surface(
  25.                     modifier = Modifier.fillMaxSize(),
  26.                     color = MaterialTheme.colorScheme.background
  27.                 ) {
  28.                     TtsScreen(tts)
  29.                 }
  30.             }
  31.         }
  32.     }
  33.    
  34.     override fun onDestroy() {
  35.         super.onDestroy()
  36.         tts?.shutdown()
  37.     }
  38. }

  39. @Composable
  40. fun TtsScreen(tts: TtsHelper?) {
  41.     Column {
  42.         Greeting("Android")
  43.         Button(onClick = {
  44.             tts?.speakWhenReady("你好, 世界!")
  45.         }) {
  46.             Text("说话")
  47.         }
  48.     }
  49. }

  50. @Composable
  51. fun Greeting(name: String, modifier: Modifier = Modifier) {
  52.     Text(
  53.         text = "Hello $name!",
  54.         modifier = modifier
  55.     )
  56. }

  57. @Preview(showBackground = true)
  58. @Composable
  59. fun GreetingPreview() {
  60.     MyTtsTestTheme {
  61.         TtsScreen(null)
  62.     }
  63. }
复制代码


主要改进点
1、添加 isInitialized 标志来跟踪 TTS 是否已完全初始化
2、在 speak 方法中检查初始化状态
3、添加 speakWhenReady 方法,可以等待 TTS 初始化完成后再播放
4、设置语言为中文 (Locale.CHINESE)
5、添加 isReady() 方法检查 TTS 状态
这样修改后,应该不会再出现 "TTS engine connection not fully set up" 的警告了。
回复

使用道具 举报

393

主题

556

帖子

3294

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3294
 楼主| 发表于 2025-9-18 16:23:34 | 显示全部楼层
第三个问题:
studio.deploy           cn.unicoder.myttstest                E  MessagePipeWrapper: Cannot write (EOF)
2025-09-18 16:22:02.138 14972-14972 studio.deploy           cn.unicoder.myttstest                E  Unable to write magic number to pipe
回复

使用道具 举报

393

主题

556

帖子

3294

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3294
 楼主| 发表于 2025-9-18 16:31:10 | 显示全部楼层
第四个问题:
C:/Users/User/.gradle/caches/transforms-3/918505438d128f58029c7c69bd324139/transformed/espresso-core-3.7.0-api.jar!/META-INF/espresso_core_java_androidx_test_espresso_action-action_kt.kotlin_module: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.9.0, expected version is 1.7.1.

## 1. 简要解释报错原因

Kotlin版本不兼容导致的编译错误。项目中使用的Kotlin编译器版本(1.7.1)与espresso-core库编译时使用的Kotlin版本(1.9.0)不匹配。

## 2. 详细原因分析

- **版本冲突**:espresso-core-3.7.0库使用Kotlin 1.9.0编译,而项目配置的Kotlin版本为1.7.1
- **元数据不匹配**:Kotlin编译后的二进制元数据版本不兼容
- **依赖库更新**:Android测试库可能自动更新到了使用新Kotlin版本编译的版本

## 3. 修复建议

### 方案一:升级项目Kotlin版本

```gradle
// 在项目的 build.gradle 文件中更新Kotlin版本
ext.kotlin_version = '1.9.0'
```
```gradle
// 或者在 plugins 块中指定版本
plugins {
    id 'org.jetbrains.kotlin.android' version '1.9.0'
}
```


### 方案二:降级依赖版本

```gradle
// 在 app/build.gradle 中指定兼容的espresso版本
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
```


### 方案三:统一Gradle插件版本

```gradle
// 在 android/build.gradle 中确保插件版本兼容
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0'
```
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|DiscuzX

GMT+8, 2025-10-25 08:46 , Processed in 0.011128 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表