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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 22:42:14