我正在编写一个文本到语音转换的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;
}
};
}
我找到了解决方案。从 MyTTSService.onCreate(( 中删除现有的等待循环。
将以下内容放在 onServiceConnected 方法的末尾
new Thread(new Runnable() {
public void run(){
readSentences();
}
}).start();
然后将方法添加到 MyTTSSer
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。
这最终应该把这个问题(已经问了好几次但从未解决(永远搁置。