在Android上等待TextToSpeech onInit()初始化

时间:2018-02-04 17:01:25

标签: android android-service text-to-speech

我正在编写一个文本到语音的Android应用程序。我正在重构代码并尝试将TextToSpeech类从活动分离到服务,这样UI可以在不阻塞的情况下进行更新,同时音频在后台播放。但是我无法等待TTS引擎初始化。

当我使用

while(isInit==false)
     Thread.sleep(1000); 

服务从不调用onServiceConnected方法。

如果有人知道如何等待TTS引擎的初始化完成,并且避免阻塞UI太长时间(导致应用程序崩溃),将非常感谢帮助!

这是我的服务

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.speech.tts.TextToSpeech;
import android.speech.tts.UtteranceProgressListener;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import java.util.HashMap;
import java.util.Locale;

public class MyTTSService extends Service {

    private static final String TAG = "Class-MyTTSService";
    private TextToSpeech tts;
    private boolean isInit = false;
    private final IBinder myBinder = new MyBinder();

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "Creating TTS Service");
        Context context = this.getApplicationContext();
        this.tts = new TextToSpeech(context, onInitListener);
        this.tts.setOnUtteranceProgressListener(utteranceProgressListener);
        Log.d(TAG, "TTS Service Created");

        // why is this blocking everything?
        while(!isInitComplete()){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Log.d(TAG, e.toString());
            }
        }
    }

    public boolean isInitComplete(){
        return isInit;
    }

    @Override
    public void onDestroy() {
        // Don't forget to shutdown tts!
        if (tts != null) {
            tts.stop();
            tts.shutdown();
        }
        super.onDestroy();
    }

    public void waitToFinishSpeaking() {
        while (tts.isSpeaking()) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Log.d(TAG, e.toString());
            }
        }
    }

    public void speak(String text, AppCompatActivity appCompatActivity) {
        Log.d(TAG, "Speak" + text);
        appCompatActivity.setVolumeControlStream(AudioManager.STREAM_MUSIC);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            HashMap<String, String> param = new HashMap<>();
            param.put(TextToSpeech.Engine.KEY_PARAM_STREAM, String.valueOf(AudioManager.STREAM_MUSIC));
            tts.speak(text, TextToSpeech.QUEUE_ADD, null);
        } else {
            String utteranceId=this.hashCode() + "";
            Bundle bundle = new Bundle();
            bundle.putInt(TextToSpeech.Engine.KEY_PARAM_STREAM, AudioManager.STREAM_MUSIC);
            tts.speak(text, TextToSpeech.QUEUE_ADD, null, null);
        }
    }

    private UtteranceProgressListener utteranceProgressListener = new UtteranceProgressListener() {
        @Override
        public void onStart(String utteranceId) {
        }

        @Override
        public void onDone(String utteranceId) {
        }

        @Override
        public void onError(String utteranceId) {
            Log.e(TAG, "Error while trying to synthesize sample text");
        }
    };

    private TextToSpeech.OnInitListener onInitListener =  new TextToSpeech.OnInitListener() {
        @Override
        public void onInit(int status) {
            if (status == TextToSpeech.SUCCESS) {
                int result = tts.setLanguage(Locale.US);
                if (result == TextToSpeech.LANG_MISSING_DATA
                        || result == TextToSpeech.LANG_NOT_SUPPORTED) {
                    Log.e("TTS", "This Language is not supported");
                } else {
                    //init success
                    isInit = true;
                    Log.d(TAG, "TTS Initialized.");
                }
            } else {
                Log.e("TTS", "Initilization Failed!");
            }
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "Binding TTS Service");
        return myBinder;
    }

    public class MyBinder extends Binder {
        MyTTSService getService() {
            return MyTTSService.this;
        }
    }

    @Override
    public boolean onUnbind(Intent intent) {
        return false;
    }
}

这是我的活动

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.EditText;
import android.widget.TextView;

import java.util.ArrayList;

public class ReaderActivity extends AppCompatActivity {

    private static final String TAG = "Class-ReaderActivity";
    EditText textBox;
    ArrayList<String> sentences = new ArrayList<String>();
    MyTTSService tts;
    boolean isBound = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_reader);
        textBox = (EditText) findViewById(R.id.readerTextArea);
        Intent intentExtras = getIntent();
        Bundle extrasBundle = intentExtras.getExtras();
        sentences = extrasBundle.getStringArrayList("sentences");
        textBox.setText(sentences.toString(), TextView.BufferType.NORMAL);
        textBox.setKeyListener(null);
    }

    @Override
    protected void onStart() {
        super.onStart();
        Intent intent = new Intent(this, MyTTSService.class);
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
        Log.d(TAG, "Waiting to bind to service");
    }

    public void readSentences(){
        for(String sentence : sentences){
            Log.d(TAG +"Sencence", sentence);
            //updateUI(sentence);
            tts.speak(sentence, this);
            tts.waitToFinishSpeaking();
        }
    }

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            MyTTSService.MyBinder binder = (MyTTSService.MyBinder) service;
            tts = binder.getService();
            isBound = true;
            readSentences();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            isBound = false;
        }
    };
}

1 个答案:

答案 0 :(得分:0)

我找到了解决方案。从MyTTSService.onCreate()中删除现有的等待循环。

将以下内容放在onServiceConnected方法的末尾

new Thread(new Runnable() {
     public void run(){
          readSentences();
     }
}).start();

然后向MyTTSService添加方法

public boolean isInit(){
     return isInit;
}

在某些情况下,可能需要重新初始化tts模块。在初始化不成功的情况下,将以下内容添加到TextToSpeech.OnInitListener.OnInit。

isInit = false;

然后最后将以下内容添加到readsentences方法

while(!tts.isInit()){
     try {
          Thread.sleep(1000);
     } catch (InterruptedException e) {
          Log.d(TAG, e.toString());
     }
}
tts.speak(sentence, this);

通过这些更改,TTS模块初始化,音频工作,活动加载和UI可以在播放音频时刷新。

这最终应该把这个问题(已被问过几次但从未解决过)放好了。