title: Wait for TextToSpeech onInit() initialization on Android
body: <p>I am writing a text-to-speech android application. I am refactoring the code and trying to separate TextToSpeech class from an activity to a service so the UI can be updated without blocking, while the audio is playing in the background. However I am not able to wait for the TTS engine to initialize. </p>
  
  <p>When I use</p>
  
  <pre><code>while(isInit==false)
       Thread.sleep(1000); 
  </code></pre>
  
  <p>the service never calls the onServiceConnected method.</p>
  
  <p>If anybody knows how to wait for initialization of the TTS engine to complete, and avoid blocking the UI for too long (which causes the application to crash), help would be greatly appreciated!</p>
  
  <p>Here is my service</p>
  
  <pre><code>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 &gt;= Build.VERSION_CODES.LOLLIPOP) {
              HashMap&lt;String, String&gt; param = new HashMap&lt;&gt;();
              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;
      }
  }
  </code></pre>
  
  <p>And here is my activity</p>
  
  <pre><code>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&lt;String&gt; sentences = new ArrayList&lt;String&gt;();
      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;
          }
      };
  }
  </code></pre>