Android TextToSpeech: speak failed: not bound to TTS engine (解决因TextToSpeech太久未使用导致的系统回收,进而无法播报问题)


import android.speech.tts.TextToSpeech;
import android.speech.tts.UtteranceProgressListener;
import android.text.TextUtils;

import java.lang.reflect.Field;
import java.util.Locale;

public class TTsUtil {

    private  static TTsUtil tTsUtil;
    public static TTsUtil getInstance() {
        if (tTsUtil == null) {
            synchronized (TTsUtil.class) {
                if (tTsUtil == null)
                    tTsUtil = new TTsUtil();
            }
        }
        return tTsUtil;
    }

    private TextToSpeech textToSpeech;
    private boolean speechOver = true;
    private TTsUtil() {
//        "com.iflytek.speechcloud" 科大讯飞
//        "com.baidu.duersdk.opensdk" 百度语音
//        "com.google.android.tts" 谷歌语音

        textToSpeech = new TextToSpeech(MyApplication.getAppContext(), status -> {
            if (status == TextToSpeech.SUCCESS) {
                int result = textToSpeech.setLanguage(Locale.CHINA);
                if (result != TextToSpeech.LANG_COUNTRY_AVAILABLE
                        && result != TextToSpeech.LANG_AVAILABLE) {
                    ToastUtils.show("TTS暂时不支持这种语音的朗读!");
                }

            }else {
                LogUtil.writerlog("TTS初始化失败!");
            }
        },"com.iflytek.speechcloud");//科大讯飞语音引擎
        textToSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() {
            @Override
            public void onStart(String utteranceId) {
                speechOver = false;
            }

            @Override
            public void onDone(String utteranceId) {
                speechOver = true;
            }

            @Override
            public void onError(String utteranceId) {
                speechOver = true;
            }
        });
    }


    public void speak(int content) {
        if (!speechOver)return;
        textToSpeech.speak(int2chineseNum(content), TextToSpeech.QUEUE_ADD, null, "jiance");
    }

    public void speak(String content) {
        LogUtil.writerlog("TTS的speechOver==false");
        if (!speechOver)return;
        if (ismServiceConnectionUsable(textToSpeech)) {//没有被回收
            textToSpeech.speak(content, TextToSpeech.QUEUE_ADD, null, "jiance");
        }else {//被回收了不可用状态
            textToSpeech = new TextToSpeech(MyApplication.getAppContext(), status -> {
                if (status == TextToSpeech.SUCCESS) {
                    int result = textToSpeech.setLanguage(Locale.CHINA);
                    if (result != TextToSpeech.LANG_COUNTRY_AVAILABLE
                            && result != TextToSpeech.LANG_AVAILABLE) {
                        ToastUtils.show("TTS暂时不支持这种语音的朗读!");
                    }
                    textToSpeech.speak(content, TextToSpeech.QUEUE_ADD, null, "jiance");
                }else {
                    LogUtil.writerlog("TTS初始化失败!");
                }
            },"com.iflytek.speechcloud");//科大讯飞语音引擎
        }

    }

    public String int2chineseNum(int src) {
        final String num[] = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"};
        final String unit[] = {"", "十", "百", "千", "万", "十", "百", "千", "亿", "十", "百", "千"};
        String dst = "";
        int count = 0;
        while(src > 0) {
            dst = (num[src % 10] + unit[count]) + dst;
            src = src / 10;
            count++;
        }
        return dst.replaceAll("零[千百十]", "零").replaceAll("零+万", "万")
                .replaceAll("零+亿", "亿").replaceAll("亿万", "亿零")
                .replaceAll("零+", "零").replaceAll("零$", "");
    }

    /**
     * TTS初始化之后有时会无法播放语音。
     * 从打印日志看failed: not bound to TTS engine
     * 找到源代码打印处
     * if (mServiceConnection == null) {
     *      Log.w(TAG, method + " failed: not bound to TTS engine");
     *   return errorResult;
     *  }
     *  通过反射判断mServiceConnection是否为空
     * @param tts
     * @return true 可用
     */
    public static boolean ismServiceConnectionUsable(TextToSpeech tts) {

        boolean isBindConnection = true;
        if (tts == null){
            return false;
        }
        Field[] fields = tts.getClass().getDeclaredFields();
        for (int j = 0; j < fields.length; j++) {
            fields[j].setAccessible(true);

                if (TextUtils.equals("mConnectingServiceConnection",fields[j].getName()) && TextUtils.equals("android.speech.tts.TextToSpeech$Connection",fields[j].getType().getName())) {
                try {
                    if(fields[j].get(tts) == null){
                        isBindConnection = false;
                        LogUtils.e("*******反射判断 TTS -> mServiceConnection == null*******");
                    }
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
        return isBindConnection;
    }

    /**
     *演示回收TextToSpeech
     */
    public  void getBackobjeckt() {
        if (textToSpeech == null){
            return;
        }else {
            textToSpeech.stop();
            textToSpeech.shutdown();
        }
    }

}

使用时候:

TTsUtil.getInstance().speak("问题找到");

摘要:解决使用谷歌自带TTS文字转语音偶尔不播报问题

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
这个问题可能是由于没有正确设置TTS引擎导致的。您可以尝试以下步骤来解决问题: 1. 确认您的设备上已经安装了TTS引擎。您可以在“设置”中找到“语音输入和输出”选项,检查您的TTS引擎是否已启用。 2. 如果您的设备上没有TTS引擎,您可以在Google Play商店中搜索并下载TTS引擎。 3. 如果您的设备上已安装TTS引擎,请确保它已启用。您可以在“设置”中找到“语音输入和输出”选项,检查您的TTS引擎是否已启用。 4. 如果您已经安装和启用了TTS引擎,但仍然遇到问题,请尝试清除TTS引擎的缓存和数据。您可以在“设置”中找到“应用程序”选项,找到您的TTS引擎并清除其缓存和数据。 5. 最后,请确保您的应用程序有权限使用TTS引擎。您可以在您的应用程序清单文件中添加以下权限: ``` <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.READ_CONTACTS"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> <uses-permission android:name="android.permission.READ_LOGS"/> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="com.android.vending.BILLING"/> <uses-permission android:name="android.permission.GET_TASKS"/> <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION"/> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/> <uses-permission android:name="android.permission.WRITE_SETTINGS"/> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/> <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW"/> <uses-permission android:name="android.permission.MANAGE_DOCUMENTS"/> <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/> <uses-permission android:name="android.permission.RECORD_VIDEO"/> <uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/> <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"/> <uses-permission android:name="android.permission.FLASHLIGHT"/> <uses-permission android:name="android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND"/> <uses-permission android:name="android.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND"/> ``` 希望这些步骤可以帮助您解决问题
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值