How to build Time Speaking clock - java

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();
}
}

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

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

StatusUpdate Discord Bot

This is my code to update the Status:
String[] status = new String[] {"Version: 1.5.0", "https://discord.gg/arWEM2h", "Love Backxtar", "You want me!", "Type: ~help", "User Counter: %members"};
int next = 60;
public void onSecond() {
if(next%5 == 0) {
if(!hasStarted) {
hasStarted = true;
StatChannelCommand.onStartUp();
}
Random rand = new Random();
int i = rand.nextInt(status.length);
shardMan.getShards().forEach(jda -> {
String text = status[i].replaceAll("%members", "" + jda.getUsers().size());
jda.getPresence().setActivity(Activity.playing(text));
});
StatChannelCommand.checkStats();
if(next == 0) {
next = 60;
}
}
else {
next--;
}
}
But the String is running every second. I thought it was every 5 seconds. I did 60 sec % 5. What is wrong with this code?
When you enter the method onSecond() for the first time, the condition next%5 == 0 will be true. The variable next will not be updated, because this happens only in the else part. So, on next run of the method next will still be 60.

Why my Java alarm clock code doesn't work properly?

I want the code to trigger the JOptionPane.
Here is the code for the working clock:
new Thread() {
public void run() {
while (true) {
GregorianCalendar cal = new GregorianCalendar();
int hour = cal.get(GregorianCalendar.HOUR);
int min = cal.get(GregorianCalendar.MINUTE);
int sec = cal.get(GregorianCalendar.SECOND);
int AM_PM = cal.get(GregorianCalendar.AM_PM);
String day_night;
if (AM_PM == 1) {
day_night = "PM";
} else {
day_night = "AM";
}
String time = hour + ":" + min + ":" + sec + " " + day_night;
lblClock.setText(time);
}
}
}.start();
Here is code I wrote to trigger alarm, but no 'play sound' is coded yet, because I can't even get the JOptionPane to appear. Why? I want to get the values from spinners, than compare to real time until they meet and than trigger alarm and exit thread. How to fix it?
btnAlarm.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
new Thread() {
public void run() {
txtAlarmSet.setVisible(true);
boolean flag = false;
GregorianCalendar g = new GregorianCalendar();
int hour = Integer.parseInt(spinnerHour.getModel().getValue().toString());
int minute = Integer.parseInt(spinnerMinute.getModel().getValue().toString());
int second = Integer.parseInt(spinnerSecond.getModel().getValue().toString());
int AMorPM;
if (rdbtnAm.isSelected()) {
AMorPM = 0;
} else
AMorPM = 1;
while (flag == false) {
int realHour = g.get(GregorianCalendar.HOUR);
int realMinute = g.get(GregorianCalendar.MINUTE);
int realSecond = g.get(GregorianCalendar.SECOND);
int realAM_PM = g.get(GregorianCalendar.AM_PM);
if (hour == realHour && minute == realMinute && second == realSecond
&& AMorPM == realAM_PM) {
JOptionPane.showMessageDialog(null, "WORKS!"); // <- this doesn't appear!
flag = true;
}
}
txtAlarmSet.setVisible(false);
}
}.start();
}
});
In your checking loop, you need to reacquire the Calendar on every pass, otherwise, you'll just end up re-checking the same time value over and over. Move the line
GregorianCalendar g = new GregorianCalendar();
inside the loop.
Note: This is not a particularly good approach to this problem. What you're doing is called "busy waiting" and it's generally not good for much other than making the CPU get hot. A better approach would be to use an event-driven approach, but that's beyond the scope of this answer.
One major problem I notice is missing } after AMorPM = 1; making it impossible to work for AM.

Countdowntimer onTick method not displaying proper seconds

For my code I use a countdown timer, however I add seconds to it as after they get an answer correct, the timer is reset to 5 seconds. The problem with this is that the text that displays the time still has the wrong number, it doesn't repeat digits. For instance if it was a 5 second timer and it goes 5,4,3 then the user gets it right, the time will go 3, 3, 3, 2, 1.
Here is my countdown code
n = 5000;
time = new TextView(this);
time.setTextColor(Color.parseColor("#FFFFFF"));
timer = new CountDownTimer(n, 1000) {
public void onTick(long millisUntilFinished) {
time.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
Intent endIntent = new Intent(MainActivity.this, Endgame.class);
endIntent.putExtra("rounds",round);
MainActivity.this.startActivity(endIntent);
}
}.start();
Then if the user gets the question right - this is the part that restarts it
if(person == false){
picturechanger();
n=5000;
timer.onTick(5000);
}
Try:
if(person == false){
picturechanger();
n=5000; // Not sure why u put n=5000 here..?
if(timer != null)
timer.cancel();
timer.start();
}

findViewById() not working when using a seperate class

Hi I am new to Android
I would like keep the following code seperatly from my MainActivity file. However, when I try to findViewById() inside the seperate class, I get the error
"cannot be resolved"
Now I know I cannot extend the MainActivity class as it will lead to stack overflow, but could someone tell me how to go about access a textview from this seperate file?
public class Counter {
private TextView tempTextView;
//Temporary TextView
private Button tempBtn;
public Handler mHandler = new Handler();
public long startTime;
public long elapsedTime;
public final int REFRESH_RATE = 100;
public String hours,minutes,seconds,milliseconds;
public long secs,mins,hrs,msecs;
public boolean stopped = false;
public Runnable startTimer = new Runnable() {
public void run() {
elapsedTime = System.currentTimeMillis() - startTime;
updateTimer(elapsedTime);
mHandler.postDelayed(this,REFRESH_RATE);
}
};
private void updateTimer (float time) {
secs = (long) (time / 1000);
mins = (long) ((time / 1000) / 60);
hrs = (long) (((time / 1000) / 60) / 60); /* Convert the seconds to String * and format to ensure it has * a leading zero when required */
secs = secs % 60;
seconds = String.valueOf(secs);
if (secs == 0) {
seconds = "00";
}
if (secs < 10 && secs > 0) {
seconds = "0" + seconds;
} /* Convert the minutes to String and format the String */
mins = mins % 60;
minutes = String.valueOf(mins);
if (mins == 0) {
minutes = "00";
}
if (
mins < 10 && mins > 0
) {
minutes = "0" + minutes;
} /* Convert the hours to String and format the String */
hours = String.valueOf(hrs);
if (hrs == 0) {
hours = "00";
}
if (hrs < 10 && hrs > 0) {
hours = "0" + hours;
}
/* Although we are not using milliseconds on the timer in this example * I included the code in the event that you wanted to include it on your own */
milliseconds = String.valueOf((long) time);
if (milliseconds.length() == 2) {
milliseconds = "0" + milliseconds;
}
if (milliseconds.length() <= 1) {
milliseconds = "00";
}
milliseconds = milliseconds.substring(milliseconds.length() - 3, milliseconds.length() - 2);
/* Setting the timer text to the elapsed time */
// ((TextView) findViewById(R.id.elapsed_value)).setText(hours + ":" + minutes + ":" + seconds);
// ((TextView)findViewById(R.id.timerMs)).setText("." + milliseconds); }
}
}
You need to inflate a view and call the mehod findViewById() from this view. To inflate a view, you need a Context (you can set it in a custom constructor)
View view;
LayoutInflater inflater = (LayoutInflater) yourContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.mylayout, null);
tempTextView = (TextView) view.findViewById(R.id.tv);
Because, findViewById() is method from Activity class. That's why you can not use it in any other Java class.
And second you can not update Android application UI from any worker thread.
So better to use AsyncTask and pass the TextView's references which you want to update after certain task.
Or use runOnMainUiThread() if you are going to update Application UI from other worker thread. But Be sure runOnUiThread() only works with Activity Context.
You could create a constructor for Counter that takes a reference to your TextView from your Activity.
public Counter(TextView tv) {
tempTextView = tv;
}
Then call findViewById() on your MainActivity as pass in the result when you're instantiating Counter.
You're already on the UI thread, no need for AsyncTask here...
You can have a constructor where you set an activity variable.
public Counter (MainActivity activity) {
mActivity = activity;
}
Then, you can call
mActivity.findViewById(...);
which will find the view in your MainActivity layout that you set in
setContentView(<layout>);

How to make a timer run in the background

How would i go about efficiently having a timer run in the background when the application is stopped? rite now i have not done anything and the timer will continue to run when the app has been stopped but some times it will stop running without me giving it the command.
This is how i am currently running my timer:
if(t == null){
t = new Timer();
t.schedule(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
if(DHPDPS==0){
money = (DPPS+Reserve);
Reserve = (money);
String end = String.format("%1f", money);
t1.setText("$" + end);
}else if(counter > DHPDPS && DOTPPS != 0 && DHPDPS != 0){
money = (DOTPPS+Reserve);
Reserve = (money);
String end = String.format("%1f", money);
t1.setText("$" + end);
} else{
money = (DPPS+Reserve);
Reserve = (money);
String end = String.format("%1f", money);
t1.setText("$" + end);
}
counter++;
//if(counter == 3000)
// t.cancel();
// Display pay per second
if(counter <= DHPDPS || DHPDPS == 0){
t2.setText("Your pay per second is: $"+result);
}else{
t2.setText("Your pay per second is: $"+result2);
}
}
});
}
}, 20, 20);
It is declared in the onCreate(), thanks!
For tasks running in the background you should be using an IntentService. It will keep running even if your activity is paused or removed by the OS.
If your phones memory starts filling up it will close all the activities that are not actively being used.
For something like a timer it might be better to save the start time into SQLite and when the activity is reloaded reference it as a start point to calculate the duration.
Otherwise, if your intent that the timer keeps ticking turn it into an intent service.
private fun startTimer()
var lastdata = PrefUtils.getpunchtime(this)
var mEndTimediff = System.currentTimeMillis() - lastdata!!
var mTimeLeftInMillis = viewModel.START_TIME_IN_MILLIS.toLong() - mEndTimediff
viewModel.mCountDownTimer = object : CountDownTimer(mTimeLeftInMillis, 1000) {
override fun onTick(millisUntilFinished: Long) {
mTimeLeftInMillis = millisUntilFinished
updateCountDownText(mTimeLeftInMillis)
}
override fun onFinish() {
viewModel.mTimerRunning = false
}
}.start()
}
private fun updateCountDownText(mTimeLeftInMillis: Long) {
val millis: Long = mTimeLeftInMillis
val hms = String.format(
"%02d : %02d: %02d", TimeUnit.MILLISECONDS.toHours(millis),
TimeUnit.MILLISECONDS.toMinutes(millis) - TimeUnit.HOURS.toMinutes(
TimeUnit.MILLISECONDS.toHours(
millis
)
),
TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES.toSeconds(
TimeUnit.MILLISECONDS.toMinutes(
millis
)
)
)
binding.tvTimertime.setText(hms)
}
SharePreference in store Last_time
fun storepunchtime(context: Context, storepunchtime: Long) {
val editor = getSharedPreferences(context).edit()
editor.putLong(PUNCH_TIME, storepunchtime)
editor.apply()
editor.commit()
}
fun getpunchtime(context: Context): Long? {
return getSharedPreferences(context).getLong(PUNCH_TIME, 0L)
}

Categories