Xamarin.Android C# TextToSpeech语言切换与谷歌TTS问题修复
问题根因
- 启动自动弹出Google TTS界面:一是初始化TTS时硬编码指定了Google TTS引擎包名,系统检测到引擎状态异常时会直接拉起引导;二是原有逻辑在
OnActivityResult中无条件触发TTS数据安装流程,加上Spinner首次绑定数据时会自动触发选中事件,应用一启动就会执行跳转逻辑。 - Spinner仅显示“Default”选项:在TTS引擎未完成初始化(
OnInit回调未触发)时就提前调用IsLanguageAvailable校验语种支持性,此时TTS实例未就绪,所有校验结果都会返回不支持,自然无法加载其他语种。同时原有逻辑仅用语言显示名做匹配和去重,还会出现同语种重复、匹配错误的问题。
具体修改点
- 移除TTS初始化时硬编码的
com.google.android.tts引擎参数,使用系统默认TTS引擎,避免强制拉起Google服务引导 - 将语种校验、Spinner数据绑定的逻辑全部移到TTS初始化成功的回调中执行,确保引擎就绪后再做语种检测
- 移除Spinner选中事件中无意义的TTS数据检查跳转逻辑,仅当选中语言确实缺少语音数据时,才弹窗提示用户是否安装,禁止无条件跳转
- 调整语种存储逻辑,直接保存支持的Locale实例,通过语言+国家编码去重,避免仅用显示名匹配导致的选项丢失、匹配错误问题
- 增加TTS就绪状态标志位,屏蔽Spinner首次绑定数据时自动触发的无效选中事件
修正后完整代码
using Android.App; using Android.Content; using Android.OS; using Android.Runtime; using Android.Views; using Android.Widget; using System; using System.Collections.Generic; using System.Linq; using System.Text; using Android.Support.V7.App; using Android.Speech.Tts; using Java.Util; using Android.Graphics; namespace DND_Connect { [Activity(Label = "Deaf")] public class DeafPage : Activity, TextToSpeech.IOnInitListener { TextToSpeech textToSpeech; Spinner spinLanguages; EditText editWhatToSay; private bool _isTtsReady = false; private List<Locale> _supportedLocales = new List<Locale>(); private Locale currentLang; protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); SetContentView(Resource.Layout.deaf); var btnSayIt = FindViewById<Button>(Resource.Id.buttonSpeak); editWhatToSay = FindViewById<EditText>(Resource.Id.edtSpch); spinLanguages = FindViewById<Spinner>(Resource.Id.spnLng); var txtSpeedVal = FindViewById<TextView>(Resource.Id.txtSpeed); var txtPitchVal = FindViewById<TextView>(Resource.Id.txtPitch); var seekSpeed = FindViewById<SeekBar>(Resource.Id.skSpeed); var seekPitch = FindViewById<SeekBar>(Resource.Id.skPitch); var txtView = FindViewById<TextView>(Resource.Id.deaftitle); var txtView1 = FindViewById<TextView>(Resource.Id.deafdesc); Typeface tf = Typeface.CreateFromAsset(Assets, "Roboto-Condensed.ttf"); txtView.SetTypeface(tf, Android.Graphics.TypefaceStyle.Normal); txtView1.SetTypeface(tf, Android.Graphics.TypefaceStyle.Normal); seekSpeed.Progress = seekPitch.Progress = 127; txtSpeedVal.Text = txtPitchVal.Text = "0.5"; // 移除硬编码的Google TTS引擎参数,使用系统默认引擎 textToSpeech = new TextToSpeech(this, this); currentLang = Locale.Default; textToSpeech.SetPitch(.5f); textToSpeech.SetSpeechRate(.5f); btnSayIt.Click += delegate { if (!_isTtsReady) { Toast.MakeText(this, "TTS引擎初始化中,请稍后", ToastLength.Short).Show(); return; } if (!string.IsNullOrEmpty(editWhatToSay.Text)) textToSpeech.Speak(editWhatToSay.Text, QueueMode.Flush, null); }; seekPitch.StopTrackingTouch += (object sender, SeekBar.StopTrackingTouchEventArgs e) => { var seek = sender as SeekBar; var progress = seek.Progress / 255f; if (_isTtsReady) textToSpeech.SetPitch(progress); txtPitchVal.Text = progress.ToString("F2"); }; seekSpeed.StopTrackingTouch += (object sender, SeekBar.StopTrackingTouchEventArgs e) => { var seek = sender as SeekBar; var progress = seek.Progress / 255f; if (_isTtsReady) textToSpeech.SetSpeechRate(progress); txtSpeedVal.Text = progress.ToString("F2"); }; spinLanguages.ItemSelected += (object sender, AdapterView.ItemSelectedEventArgs e) => { // 屏蔽初始化阶段自动触发的选中事件 if (!_isTtsReady) return; if (e.Position == 0) { currentLang = Locale.Default; } else { currentLang = _supportedLocales[e.Position - 1]; } var setResult = textToSpeech.SetLanguage(currentLang); // 仅当语言数据缺失时才提示安装,不直接跳转 if (setResult == LanguageAvailableResult.MissingData) { new AlertDialog.Builder(this) .SetMessage("当前语言缺少TTS语音数据,是否前往安装?") .SetPositiveButton("安装", (s, args) => { var installIntent = new Intent(TextToSpeech.Engine.ActionInstallTtsData); StartActivity(installIntent); }) .SetNegativeButton("取消", (s, args) => { }) .Show(); } }; } void TextToSpeech.IOnInitListener.OnInit(OperationResult status) { if (status == OperationResult.Success) { _isTtsReady = true; _supportedLocales.Clear(); List<string> langDisplayList = new List<string> { "Default" }; // 引擎就绪后再加载支持的语种 foreach (var locale in Locale.GetAvailableLocales()) { LanguageAvailableResult res = textToSpeech.IsLanguageAvailable(locale); if (res == LanguageAvailableResult.Available || res == LanguageAvailableResult.CountryAvailable || res == LanguageAvailableResult.CountryVarAvailable) { // 按语言+国家编码去重,避免重复选项 if (!_supportedLocales.Any(l => l.Language == locale.Language && l.Country == locale.Country)) { _supportedLocales.Add(locale); langDisplayList.Add(locale.DisplayName); } } } langDisplayList = langDisplayList.OrderBy(t => t).Distinct().ToList(); var adapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleSpinnerDropDownItem, langDisplayList); spinLanguages.Adapter = adapter; spinLanguages.SetSelection(0); textToSpeech.SetLanguage(currentLang); } else { Toast.MakeText(this, "TTS引擎初始化失败,请检查系统语音设置", ToastLength.Long).Show(); } } } }
注意:如果需要使用特定TTS引擎,可在设备系统设置中手动修改默认语音引擎,不要在代码中硬编码包名强制拉起对应服务。
内容的提问来源于stack exchange,提问作者CoffeeBoi
相关产品推荐
相关产品推荐

