当前位置: 首页 > 工具软件 > Text::Unit > 使用案例 >

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

翟誉
2023-12-01

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文字转语音偶尔不播报问题

 类似资料: