1

I would need some help with Android Studio. I'm trying to develop a simple Android Activity which should speak, listen and then answer back to user's question. First things first, I'm trying to make the Activity simply pronounce a generic phrase. My issue is that, once initialized, TextToSpeech does not pronounce anything if instruction is written outside of a Button listener. Some code should clear things up:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ImageView imgView = findViewById(R.id.emote);
        Button helloBtn = findViewById(R.id.sayBtn);

        EmoteController emoteController = EmoteController.getInstance(MainActivity.this, imgView);
        emoteController.setEmote(Emote.DOUBTFUL);

        tts = new TextToSpeech(getApplicationContext(), new TextToSpeech.OnInitListener() {
            @Override
            public void onInit(int i) {
                if(i != TextToSpeech.ERROR){
                    tts.setLanguage(Locale.ENGLISH);
                    /*THIS SPEAK DOES WORK WHEN TEXTTOSPEECH VARIABLE IS INITIALIZED!*/
                    tts.speak("Initialized!", TextToSpeech.QUEUE_FLUSH, null, null);
                }
                else{
                    Toast.makeText(getApplicationContext(), "Failed to initialize TextToSpeech", Toast.LENGTH_SHORT).show();
                }
            }
        });

        helloBtn.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                /*THIS SPEAK DOES IF WORK IF BUTTON IS CLICKED!*/
                tts.speak("Speech from Button!", TextToSpeech.QUEUE_ADD, null, null);
            }
        });

        /*-->THIS SPEAK DOES NOT WORK!<--*/
        tts.speak("Speech from on create!", TextToSpeech.QUEUE_ADD, null, null);
    }

As you see, in provided code I use speak method 3 times: one in tts initialisation, another one in Button's listener and the last one in onCreate(Bundle) method. First two work good, last one does not speak at all. My goal here is to communicate with Activity without Buttons or anything else, since the Activity it's just an ImageView. Once App starts, it should ask a question, wait for an answer and then process the answer. Any idea of why only first two speak() methods work but not the third one? I don't think it matters, but for completeness I let you guys see onResume method too:

@Override
    public void onResume() {
        super.onResume();
        View decorView = getWindow().getDecorView();
        int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
        decorView.setSystemUiVisibility(uiOptions);
    }

Hope I've been clear, Thank you very much

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
Sergio
  • 354
  • 1
  • 12

1 Answers1

2

Keyword here is "asynchronous"

The initialization of new TextToSpeech instance doesn't finish right after this line because it is an asynchronous process

tts = new TextToSpeech(..)

Whenever you see a method which required a xxxListener or xxxCallback as a parameter, it must be an async method like this. The work this method is doing will be finished at other moment in the future, not "now".

That's mean right after this line, tts has been not an instance of TextToSpeech yet, so this call will not work

/*-->THIS SPEAK DOES NOT WORK!<--*/
tts.speak("Speech from on create!", TextToSpeech.QUEUE_ADD, null, null);

Other two calls worked because they are called in the future.

The former is called in onInit() callback method of Listener object when instance is actually initialized.

The latter is called when you click the button, it's long enough to be sure that everything is initialized.

Miller Go Dev
  • 545
  • 4
  • 7
  • Thanks for your answer. So in order to achieve my goal, what do I have to do? – Sergio Jul 12 '19 at 17:34
  • I think calling tts.speak in onInit() solved your problem, right? Or I misunderstood something? – Miller Go Dev Jul 13 '19 at 06:44
  • Yes, you are right. Is that the right way to proceed though? If I have to use speak(...) then listen for user answer and then speak(...) again multiple times, is it a good way to proceed? – Sergio Jul 13 '19 at 10:52
  • Oh so you want to make things like a continuous conversation between user and your app. I think you should use LiveData and ViewModel. Whenever tts initialization finished or user speaking finished, you set a LiveData variable in ViewModel to be true (ex. shouldTtsSpeak.value = true). Then in your activity or fragment, you listen to change event of this variable to trigger tts.speak() – Miller Go Dev Jul 13 '19 at 13:27