问题
I'm trying to get TTS to run in the background. But, I never get any sound. I have a broadcast receiver which starts a service. I put my TTS code in both of those, but it never speaks. I know the method is being called (I put a breakpoint on it), but it still doesn't work.
Here's my log, but it doesn't seem to contain anything about the TTS service.
10-04 22:45:30.663: WARN/InputManagerService(209): Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy@4423df40
10-04 22:45:37.363: INFO/PollingManager(449): calculateShortestInterval(): shortest interval is 540000
10-04 22:45:37.413: INFO/TLSStateManager(449): org.apache.harmony.nio.internal.SocketChannelImpl@4400ece0: Wrote out 29 bytes of data with 0 bytes remaining.
10-04 22:45:38.043: ERROR/IMAPEmailService(480): Can't create default IMAP system folder Trash. Please reconfigure the folder names.
10-04 22:45:40.123: ERROR/EONS(303): EF_PNN: No short Name
10-04 22:45:41.543: ERROR/WMSTS(171): Month is invalid: 0
10-04 22:45:42.043: WARN/AudioFlinger(172): write blocked for 212 msecs, 24 delayed writes, thread 0xb998
Thanks everyone in advance!
回答1:
It would help to see your TTS code to make it easier for people to help you. Since I already have TTS working in a BroadcastReceiver, here's an example trimmed down from my code.
public static class TTS extends Service implements TextToSpeech.OnInitListener, OnUtteranceCompletedListener {
private TextToSpeech mTts;
private String spokenText;
@Override
public void onCreate() {
mTts = new TextToSpeech(this, this);
// This is a good place to set spokenText
}
@Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
int result = mTts.setLanguage(Locale.US);
if (result != TextToSpeech.LANG_MISSING_DATA && result != TextToSpeech.LANG_NOT_SUPPORTED) {
mTts.speak(spokenText, TextToSpeech.QUEUE_FLUSH, null);
}
}
}
@Override
public void onUtteranceCompleted(String uttId) {
stopSelf();
}
@Override
public void onDestroy() {
if (mTts != null) {
mTts.stop();
mTts.shutdown();
}
super.onDestroy();
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}
Start the TTS service at the point in your BroadcastReceiver where you want it to speak:
context.startService(new Intent(context, TTS.class));
I hope this helps someone if not the asker (I'm sure he got it working by now).
回答2:
you can also try this,if the text to be spoken is coming from a broadcast listener.first create a service
public class MyTell extends Service implements OnInitListener{
public MyTell() {
}
public static TextToSpeech mTts;
@Override
public IBinder onBind(Intent intent) {
return null;
}
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
mPreferences = getSharedPreferences(Mysettings.PREF_NAME, Service.MODE_PRIVATE);
pit = Float.parseFloat(mPreferences.getString("pit","0.8"));
rate = Float.parseFloat(mPreferences.getString("rate","1.1"));
mTts = new TextToSpeech(this, this);
super.onStart(intent, startId);
}
public void onInit(int status) {
// TODO Auto-generated method stub
if (status == TextToSpeech.SUCCESS) {
if (mTts.isLanguageAvailable(Locale.UK) >= 0)
Toast.makeText( MyTell.this,
"Sucessfull intialization of Text-To-Speech engine Mytell ",
Toast.LENGTH_LONG).show();
mTts.setLanguage(Locale.UK);
mTts.setPitch(pit);
mTts.setSpeechRate(rate);
} else if (status == TextToSpeech.ERROR) {
Toast.makeText(MyTell.this,
"Unable to initialize Text-To-Speech engine",
Toast.LENGTH_LONG).show();
}
}}
then create the listener where you're insert your text
public class MyBroadCast extends BroadcastReceiver {
public MyPop() {
}
@Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
//here is where you're use the service you created to speak the text
MyTell.mTts.speak("Text to be spoken", TextToSpeech.QUEUE_FLUSH,null);
}
}
make sure you start the service before you use the tts engine and also check if a tts engine is available
回答3:
Its working for me (just add on mainfest permision)
public class TES extends Service implements TextToSpeech.OnInitListener {
private TextToSpeech tts;
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
if (tts != null) {
tts.stop();
tts.shutdown();
}
super.onDestroy();
}
@Override
public void onStart(Intent intent, int startId) {
tts = new TextToSpeech(this, this);
speakOut();
}
@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");
}
speakOut();
} else {
Log.e("TTS", "Initilization Failed!");
}
}
private void speakOut() {
tts.speak("its working", TextToSpeech.QUEUE_FLUSH, null);
}
}
回答4:
Android TTS is a bounded service. Broadcast receiver has a limited context and can't bind himself to any service. However, It can START a service. All the examples shown here are of services that starting the TTS engine and of receiver that starts them. You can also do it with activity but if you don't need UI a service is better. I just think it's a good idea to understand how it works and why is works. Good luck.
回答5:
Using Kotlin, the above answers can be re-written as:
Receiver
:
class MyReceiver : BroadcastReceiver() {
val ttsService = Intent(context, TTS::class.java)
context.startService(ttsService)
}
Service
:
class TTS : Service(), TextToSpeech.OnInitListener {
private var mTts: TextToSpeech? = null
private var spokenText: String? = null
override fun onCreate() {
mTts = TextToSpeech(this, this)
// This is a good place to set spokenText
spokenText = "Hello!.."
}
override fun onInit(status: Int) {
if (status == TextToSpeech.SUCCESS) {
val result = mTts!!.setLanguage(Locale.US)
if (result != TextToSpeech.LANG_MISSING_DATA && result != TextToSpeech.LANG_NOT_SUPPORTED) {
Thread().run {
mTts!!.apply {
speak(spokenText, TextToSpeech.QUEUE_FLUSH, null, null)
}
Thread.sleep(10000)
stopSelf()
}
}
} else if (status == TextToSpeech.ERROR) {
stopSelf()
}
}
override fun onDestroy() {
if (mTts != null) {
mTts!!.stop()
mTts!!.shutdown()
}
super.onDestroy()
}
override fun onBind(arg0: Intent): IBinder? {
return null
}
}
And in the Manifest
:
<receiver
android:name=".MyReceiver">
<intent-filter>
<action android:name="android.intent.action.xxxx" />
</intent-filter>
</receiver>
<service android:name=".TTS" />
回答6:
Android-O onwards using service for things like this has background restrictions. One can use JobIntentService to achieve the same as shown here.
来源:https://stackoverflow.com/questions/3860711/start-android-tts-from-broadcast-receiver-or-service