I am trying to fire a Text to speech service from an activity and the activity based on certain events would cause the appropriate string to be sent to the service which speaks out.
Here is my TTSService:
public class TTSService extends Service implements TextToSpeech.OnInitListener{
private String str;
private TextToSpeech mTts;
private static final String TAG="TTSService";
public static TTSService sInstance;
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public void onCreate() {
mTts = new TextToSpeech(this,
this // OnInitListener
);
mTts.setSpeechRate(0.5f);
Log.v(TAG, "oncreate_service");
str ="turn left please ";
super.onCreate();
sInstance=this;
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
if (mTts != null) {
mTts.stop();
mTts.shutdown();
}
super.onDestroy();
}
@Override
public void onInit(int status) {
Log.v(TAG, "oninit");
if (status == TextToSpeech.SUCCESS) {
int result = mTts.setLanguage(Locale.US);
if (result == TextToSpeech.LANG_MISSING_DATA ||
result == TextToSpeech.LANG_NOT_SUPPORTED) {
Log.v(TAG, "Language is not available.");
} else {
sayHello(str);
}
} else {
Log.v(TAG, "Could not initialize TextToSpeech.");
}
}
public void sayHello(String str) {
mTts.speak(str,
TextToSpeech.QUEUE_FLUSH,
null);
}
}
Here is my activity's code to create the service:
public void onCreate(Bundle savedInstanceState) {
//rest of code.....
Intent serviceIntent = new Intent();
serviceIntent.setAction("com.packagename.texttospeech.TTSService");
startService(serviceIntent);
}
Here is the activity's onSensorChanged event handler:
@Override
public void onSensorChanged(SensorEvent event) {
float distance = event.values[0];
while(TTSService.sInstance==null){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
TTSService.sInstance.sayHello(Float.valueOf(distance).toString());
}
Now when I run the activity above, it hangs and does not respond.
On removing the while loop above, I get the following error trace:
ERROR/AndroidRuntime(7469): FATAL EXCEPTION: main
java.lang.NullPointerException
at com.packagename.texttospeech.SensorTestActivity.onSensorChanged(SensorTestActivity.java:51)
at android.hardware.SensorManager$ListenerDelegate$1.handleMessage(SensorManager.java:456)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4633)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
at dalvik.system.NativeStart.main(Native Method)
So clearly the problem is that in the line(SensorTestActivity.java:51
):
TTSService.sInstance.sayHello(Float.valueOf(distance).toString());
Here the sInstance
is null which suggests that TTSService's onCreate()
is yet to be finished.So how should I make my activity wait till the TTSService
is ready to be used?
You don't. Most likely, you get rid of the service entirely, as it does not appear to be necessary. Have the activity use
TextToSpeech
directly.If you have a demonstrable reason why your app needs this to be in a service:
Step #1: Delete
public static TTSService sInstance
and thesayHello()
method.Step #2: Get rid of your existing
startService()
call.Step #3: Replace
TTSService.sInstance.sayHello(Float.valueOf(distance).toString());
with astartService()
call, to send a command to the service, where the message to be said is added as aString
extra.Step #4: In
onStartCommand()
of your service, if the TTS initialization is complete, callspeak()
to speak the requested string (pulled from the extra). If the TTS initialization is not yet complete, append the string to anArrayList<String>
.Step #5: In
onInit()
, replace yourNullPointerException
-generatingsayHello()
call with a loop over theArrayList<String>
contents tospeak()
each of them.This way, your activity does not care whether the TTS engine is ready or not. It simply sends the request to the service, which queues it up until TTS is ready, at which time it will be played.