Can I use static TextToSpeech in Android?

The TextToSpeech constructor looks like it "belongs" to an Activity. I am creating an application with several different actions, and I do not want to initialize a new TextToSpeech instance for everyone - I want the speech to go smoothly, even if the activity changes.

My idea is to have a static TextToSpeech object accessed by all the actions initialized first.

  • Does anyone know if the implementation of TextToSpeech is thread safe? I guess not, but someone out there might know.
  • If I initialize it in the context of my default action, will the TextToSpeech instance stop working when the action is destroyed?
+4
source share
5 answers

Thanks to those who told me to pass ApplicationContext. It turned out that it was an easy bit ... The hard bit was whether the TextToSpeech object was guaranteed to be thread safe.

Thanks for the answers telling me how to make something thread safe / assuming this is the case, but the question was whether the object is already there. I probably should have said that I was fine with implementing security flows, but I wanted to know if I needed to worry. And I don't want to assume thread safety without being sure.

I ran the following and it seemed to work. Therefore, I believe that the Android TTS SDK is thread safe, but cannot find any documentation that says it is safe to read this on all devices, so I will wrap my copy of TTS for now!

package com.example.testproject; import java.util.Random; import android.os.Bundle; import android.app.Activity; import android.speech.tts.TextToSpeech; import android.speech.tts.TextToSpeech.OnInitListener; public class TestActivity extends Activity implements OnInitListener { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); tts = new TextToSpeech(getApplicationContext(), this); } TextToSpeech tts = null; @Override public void onInit(int arg0) { for (int i = 0; i < 100; ++i) { class Irritate implements Runnable { Irritate(int iIn) { i = iIn; } @Override public void run() { Random r = new Random(); try { Thread.sleep(r.nextInt(2000)); } catch (InterruptedException e) { e.printStackTrace(); } tts.speak(Integer.toString(i), TextToSpeech.QUEUE_ADD, null); } int i; } Thread t = new Thread(new Irritate(i)); t.start(); } } } 
+3
source

I have never tried this, but I think that you can pass the application context as a parameter in the constructor, not necessarily Activity.

But, paying attention to the documentation, I see that the TTS mechanism has its own quering system, so you can call several times without worrying about thread synchronization.

Answering your questions, I'm not sure about number two, but, as I wrote at the beginning, I would try to convey the context of the application, not the context of activity.

About the first, well, perhaps, one instance per engine at a time. And you usually only have one engine, but then again, if the engine manages requests, don't worry about threads.

+4
source

I always used TTS as the activity that I started ForResult. I just shoot this intention, and then wait for it to return. If I remember correctly, if it returns an array of answers, sorted by confidence. So, if you do not have a Context, then I do not believe that there is another way to call it (at least using this model). Not sure if there is an object reference you can get.

However, if there is, use your idea. Then you can simply expand the application and save a static link to your TTS. Thus, it will be displayed for all your actions. I think this is the answer you are looking for.

+1
source

Above was helpful to help me solve this problem. In my case, I also had a snippet, and I did the following:

From a fragment (from a fragment you want to say “getActivity (). GetApplicationContext ()” instead of “getApplicationContext ()"):

 public void onActivityResult(int requestCode, int resultCode, Intent data){ if(requestCode == MY_DATA_CHECK_CODE){ if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) { tts = new TextToSpeech(getActivity().getApplicationContext(), new TextToSpeech.OnInitListener() { @Override public void onInit(int status) { if(status == TextToSpeech.SUCCESS){ result = tts.setLanguage(Locale.UK); } } }); } else { // missing data, install it Intent installIntent = new Intent(); // The ACTION_INSTALL_TTS_DATA intent will take the user to Android Market, and will let the user initiate the download installIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA); startActivity(installIntent); } } } 
0
source

TextToSpeech is not thread safe with the GUI because the TextToSpeech listener method is called from a thread other than the GUI.

If your listener methods interact with the GUI, you will have to include code to make GUI changes in Looper for the GUI stream.

There are many examples of how to wrap a GUI command in a handler and put it in the looper of the GUI thread. Here is a sketch of what you would do:

 public class SpeechUtteranceListener extends UtteranceProgressListener { @Override public void onDone(String utteranceId) { Runnable guiCommand = new Runnable() { @Override public void run() { someButton.setEnabled(true); } } }; runOnUiThread(asrStartCommand); } private void runOnUiThread(Runnable command){ Looper.getMainLooper().post(command); } } 
0
source

All Articles