Home > Software design >  How to build Time Speaking clock
How to build Time Speaking clock

Time:01-12

I new to Android programming and I want to build Time Speaking clock that will speak the current time in every hour.

Please help me with my code, I want it to say the current time in every hour, but It say it in every second, here is my code.

......................... .........................................................................................................

/** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        tts = new TextToSpeech(this, this);

         time_textView = findViewById(R.id.time_textView);
         hour_textView = findViewById(R.id.hour_textView);
        
        
        final Handler handler = new Handler();
        final Runnable runnable = new Runnable() {
            @Override
            public void run() {
                
                Calendar calendar = Calendar.getInstance();
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("h:mm:ss", Locale.getDefault());
                String currentTime = simpleDateFormat.format(calendar.getTime());
                time_textView.setText(currentTime);
                
                Hour = calendar.getTime().getHours();
                Minute = calendar.getTime().getMinutes();
                
                if (Hour == 1 && Minute == 00){
                    tts.speak("The time is 1 O'clock", TextToSpeech.QUEUE_FLUSH,null);
                }
                else if (Hour == 2 && Minute == 00){
                    tts.speak("The time is 2 O'clock", TextToSpeech.QUEUE_FLUSH,null);
                }
                else if (Hour == 3 && Minute == 00){
                    tts.speak("The time is 3 O'clock", TextToSpeech.QUEUE_FLUSH,null);
                }
                else if (Hour == 4 && Minute == 00){
                    tts.speak("The time is 4 O'clock", TextToSpeech.QUEUE_FLUSH,null);
                }
                else if (Hour == 5 && Minute == 00){
                    tts.speak("The time is 5 O'clock", TextToSpeech.QUEUE_FLUSH,null);
                }
                if (Hour == 6 && Minute == 00){
                    tts.speak("The time is 6 O'clock", TextToSpeech.QUEUE_FLUSH,null);
                }
                
                handler.postDelayed(this, 1000);
            }
        };
        handler.post(runnable);
    }
    
    @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", "Language not supported");
            } else {
            }

        } else {
            Log.e("TTS", "Initialization Failed!");
        }
    }
    
    @Override
    public void onDestroy() {
        // Don't forget to shutdown tts!
        if (tts != null) {
            tts.stop();
            tts.shutdown();
        }
        super.onDestroy();
    }
}

CodePudding user response:

I am afraid you created an infinite loop. You created the Runnable and submitted it to the queue handler.post(runnable);. Then inside the run() method you submit it with 1 second delay on with handler.postDelayed(this, 1000);.

This is why it's triggered every second. What time does the time_textView show?

There are better ways how to run scheduled tasks, check on JobScheduler for example

CodePudding user response:

I'm not sure if this is "the right way" to do it, but for the sake of "code sanity" this would be my approach (posting only the modified code):

... 

// we move this here, as there's no need to initialize it every time
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("h:mm:ss", Locale.getDefault());

final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
    @ Override
    public void run() {

        Calendar calendar = Calendar.getInstance();
        // we save our "now" as a reference so it does not "drift"/"shift" while the code is running
        Date time = calendar.getTime();
        String currentTime = simpleDateFormat.format(time);
        time_textView.setText(currentTime);
        
        // use lowercase for the first letter of variable names otherwise it gets confusing ... 
        // for ex. my variable "time" of type Date, if it was named "Time" ... 
        //  when I would write "Time.getHours()" to get the hours ... One might think that there's a 
        // Class named "Time" ('cause classes usually start with capital letters) and this class has 
        // some static method "getHours", so who reads the code is forced to check to see that it was a variable
        hour = time.getHours();
        minute = time.getMinutes();
        seconds = time.getSeconds();
        if (minute == 0 && seconds == 0) {
            // as said in some comment before, you should only check the minutes and seconds
            // the message string could be a constant and insert the hour value using String.format()
            // for optimized performance, but my Java skills are too rusty for that right now
            tts.speak("The time is "   hour   " O'clock", TextToSpeech.QUEUE_FLUSH, null);
        }
        handler.postDelayed(this, 1000);
        // actually here instead of delaying for 1 second ... you could calculate the "remaing time", how many seconds are
        // missing until the next XX:00:00, and delay for that much
        // for extra "precision", just in case, ... delay only for something like "remaingTime - 10" (or something) and 
        // if the "remaingTime < 10" delay only for 1 second, this way you can be more sure you'll not be missing the 
        // XX:00:00 ... but do this only if you notice "imprecisions" while using postDelayed with long intervals
        // and you care about them

    }
};
handler.post(runnable);
... 
  • Related