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);
...