My Countdown Timer Stuck when phone screen is locked - java

I have developed a workout app. I've two timers on the screen one is for the total timer and one for exercise time also some tts and MediaPlayer sounds. When the screen is locked my exercise timer is stuck after 10 seconds but my total remaining time timer is still running. So confused about why is it happening, I've verified battery optimization permission on\off but the issue is still the same. I've set a toast in tick function and I turn off the screen when I come back toast is showing but my timer is stuck. Can anyone help to get out of this? Thanks in advance. Countdown works fines when the screen is opened or connected to the charger.
Exercise Timer code below...
excerciseCountDownTimer = new CountDownTimer(seconds * 1000, 1000) {
public void onTick(long millisUntilFinished) {
totalExcerciseSec = (int) (millisUntilFinished / 1000);
int currentMinute = totalExcerciseSec / 60;
int currentSecond = totalExcerciseSec % 60;
binding.workoutTimeTv.setText(String.format("%02d", currentMinute) + ":" + String.format("%02d", currentSecond));
if (totalExcerciseSec == 0) {
totalRemaingCountDownTimer.cancel();
onExerciseCompleteActions();
}
}
public void onFinish() {
}
}.start();
Total Remaining Timer code below...
totalRemaingCountDownTimer = new CountDownTimer(seconds * 1000, 1000) {
public void onTick(long millisUntilFinished) {
totalRemainingSecs = (int) (millisUntilFinished / 1000);
int minutes = totalRemainingSecs / 60;
int second = totalRemainingSecs % 60;
timerPlaying = true;
binding.totalRemainingTimeTv.setText(String.format("%02d", minutes) + ":" + String.format("%02d", second));
}
public void onFinish() {
}
}.start();

Your activity is getting stopped or destroyed and that's why your timer gets stuck.
To keep the timer running even if the app is closed or killed, see this way:-
You can use this technique to detect how long the user was inactive (even when the app is in the background).
Create a SharedPreference & its Editor object. Then declare 3 long variables such:
mMillisUntilFinished = pref.getLong("millisUntilFinished",60*1000); // Replace with your time
long userExitedMillis = pref.getLong("userExitedMillis",0);
long timeLeft = mMillisUntilFinished - (System.currentTimeMillis() - userExitedMillis);
Pass timeLeft as millisInFuture. Inside timer, assign millisUntilFinished to a public variable in every tick
new CountDownTimer(timeLeft,1000){
#Override
public void onTick(long millisUntilFinished) {
Log.d("TAG", "Time left : " + millisUntilFinished/1000 + " sec");
mMillisUntilFinished = millisUntilFinished;
}
#Override
public void onFinish() {
// Timer completed
}
}.start();
Save this mMillisUntilFinished variable & current time in shared preference at onStop().
#Override
protected void onStop() {
super.onStop();
editor.putLong("millisUntilFinished",mMillisUntilFinished);
editor.putLong("userExitedMillis",System.currentTimeMillis());
editor.apply();
}
Tip : If you subtract userExitedMillis from System.currentTimeMillis() then you will get the activity inactive time (in mili second).

I have used this class to solve my issue according to my requirements.
https://gist.github.com/Gautier/737759

Related

How do I reset a Timer in Java?

So I'm trying to program a handheld electronic game, called Lights Out Cube, in Java using Eclipse Oxygen.2, and I decided to include a timer so that the player knows how much time was required by him to finish the game. When the player clicks on a button called "Start/Reset"(I change its text to "Reset" after clicking it once), which is where I activate the timer, the game starts. After every click I check if player has finished the game, and if he does, I stop the timer. If he wishes to play again, I want the timer to restart. Please help me out here:
//here i have a function called checkIfWinning() which does the checking; if there is a winner, the following code is executed to stop the timer
timer.cancel();
timer.purge();
//timer is a publicly declared java.util.Timer
//this is a code snippet for btnStart with "time" recording the time in seconds
time=0;
timer.schedule(new TimerTask()
{
#Override
public void run()
{
time++;
int hours = (int) time / 3600;
int remainder = (int) time - hours * 3600;
int mins = remainder / 60;
remainder = remainder - mins * 60;
int secs = remainder;
timeTaken.setText(String.format("%02d:%02d:%02d",hours,mins,secs));
}
}, 1000,1000);
Is there anyway this can be done? Or will I have to remove the timer entirely?
You can't reset when the TimerTask object will be activated, but in your specific case, you can reset the game time count without removing and recreating the timer.
Since your timer is fired every second, all you have to do is reset the time variable you are using, when the user clicks the reset button.
I am editing this answer based on Hulks and your comments:
Hulk is right, and you should use AtomicInteger for your time count. If you keep the timer running, there could be a bug some times where the value will not reset.
You can have an AtomicBoolean flag that lets the TimerTask know if the player is playing or not.
Here is a code example:
AtomicInteger time = new AtomicInteger();
//whenever you want to reset it:
time.set(0);
AtomicBoolean isPlaying = new AtomicBoolean();
//when user clicks "start":
isPlaying.set(true);
//when user wins or clicks "reset"
isPlaying.set(false);
//your timer task will look something like this:
public void run() {
if (isPlaying.get()) {
int currentTime = time.incrementAndGet();
int hours = (int) currentTime / 3600;
int remainder = (int) currentTime - hours * 3600;
int mins = remainder / 60;
remainder = remainder - mins * 60;
int secs = remainder;
timeTaken.setText(String.format("%02d:%02d:%02d",hours,mins,secs));
}
}
This might be clear.
You can't reset or pause the Timer in Java, but the functionality can be achieved by not running the Timer based on a boolean check.
As previously said by Hulk and Lev.M, AtomicInteger can be used in need of thread safety.
Whole logic in run() can be simplified using TimeUnit for converting seconds to the specified format,
time+=1000;
System.out.println(String.format("%02d:%02d:%02d", TimeUnit.SECONDS.toHours(time), TimeUnit.SECONDS.toMinutes(time), time%60));
import java.util.Timer;
import java.util.TimerTask;
public class Game
{
private static int time = 0;
private static Timer t = new Timer();
private static Game g;
private static boolean ispaused = false;
public static void main(String[] args)
{
t.schedule(new TimerTask() {
public void run()
{
if(ispaused)
{
return;
}
time++;
System.out.println(String.format("%02d:%02d:%02d", TimeUnit.SECONDS.toHours(time), TimeUnit.SECONDS.toMinutes(time), time%60));
}
}, 1000, 1000);
g = new Game();
try
{
System.out.println("Starting first game");
g.startGame(); Thread.sleep(5000); g.endGame();
System.out.println("Starting second game.");
g.startGame(); Thread.sleep(5000); g.endGame();
}
catch(Exception e)
{}
}
private void startGame()
{
time = 0;
ispaused = false;
System.out.println("Game Started");
}
private void endGame()
{
time = 0;
ispaused = true;
System.out.println("Game ended");
}
};

Android CountDown Set Seconds to edittext

I can set only minutes on my countdown using edit text, how about it can set also seconds on edit text on the countdown timer, any help guys don't have any clue how to set seconds
public void onClick(View v) {
switch (v.getId()) {
case R.id.startTimer:
//If CountDownTimer is null then start timer
if (countDownTimer == null) {
String getMinutes = minutes.getText().toString();//Get minutes from edittexf
//Check validation over edittext
if (!getMinutes.equals("") && getMinutes.length() > 0) {
int noOfMinutes = Integer.parseInt(getMinutes) * 60 * 1000;//Convert minutes into milliseconds
startTimer(noOfMinutes);//start countdown
startTimer.setText(getString(R.string.stop_timer));//Change Text
} else
Toast.makeText(MainActivity.this, "Please enter no. of Minutes.", Toast.LENGTH_SHORT).show();//Display toast if edittext is empty
} else {
//Else stop timer and change text
stopCountdown();
startTimer.setText(getString(R.string.start_timer));
}
break;
case R.id.resetTimer:
stopCountdown();//stop count down
startTimer.setText(getString(R.string.start_timer));//Change text to Start Timer
countdownTimerText.setText(getString(R.string.timer));//Change Timer text
break;
}
}
You can try this to show minutes and seconds:
new CountDownTimer(90000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
String text = String.format(Locale.getDefault(), "Time Remaining %02d min: %02d sec",
TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished) % 60,
TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) % 60);
tvTime.setText(text);
}
});
Change the initialization of countDownTimer according to your needs
IMO, startTimer accepts milliseconds as its parameters. You cannot set the Timer in seconds there. But use this to show seconds:
startTimer.setText(Integer.parseInt(getString(R.string.stop_timer)) / 1000);
This shows the timer in Seconds.
Hope it helps.

making a timer 12 am from now

Hello i am creating a timer in my app but i stuck in getting seconds left in day end from now (12.00 AM) my timer basically need to show time left for today 11-59 PM. I successfully created a timer function which takes inputs in seconds and then start countdown but i am unable to calculate remaining time of today in seconds
Below is my timer function
time = 30;
// Here i need time left for today end for example current time is 11.55 then remaining time is 5 minutes in seconds (300)
public void startTimer() {
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
textTimer.setText("0:"+checkDigit(time));
time--;
}
public void onFinish() {
textTimer.setText("try again");
}
}.start();
}
public String checkDigit(int number) {
return number <= 9 ? "0" + number : String.valueOf(number);
}
remaining time of today in seconds:
Calendar tomorrow = Calendar.getInstance();// creating a calendar for tomorrow at 12am
tomorrow.add(Calendar.DAY_OF_YEAR, 1);
tomorrow.set(Calendar.HOUR_OF_DAY, 0);
tomorrow.set(Calendar.MINUTE, 0);
tomorrow.set(Calendar.SECOND, 0);
tomorrow.set(Calendar.MILLISECOND, 0);
remainingSeconds = ( tomorrow.getTimeInMillis() - System.currentTimeMillis() ) / 1000

Timer may not have been Initialised?

public void reverseTimer(int Seconds,final TextView tv,final Button button,final TextView txt2){
final CountDownTimer CountDownTimer1 = new CountDownTimer(Seconds* 1000+1000, 1000) {
public void onTick(long millisUntilFinished) {
int seconds = (int) (millisUntilFinished / 1000);
int minutes = seconds / 60;
seconds = seconds % 60;
tv.setText("Time : " + String.valueOf(minutes)
+ ":" + String.valueOf(seconds));
}
public void onFinish() {
if(score > highscore)
sethighscore(txt2);
tv.setText("Completed");
Reset(tv,button,txt2);
}
}.start();
}
I have a reset button that set's the 'clicked' to true and a Reset function that is called when the reset button is pressed or when the timer finishes, I tried adding the following condition to the 'OnTick':
if(clicked == true)
{
CountDownTimer1.cancel();
}
But I get the error that it may not have been initialised I know what it means I just don't understand where to initialise it and how? or is there a different way I can stop it outside of this function?
You are creating an abstract subclass of CountDownTimer. All the code in onTick and onFinish belong to that that object.
Inside those methods, you can reference the object with this. So you can simply do:
this.cancel();
Or even just:
cancel();

Combine two services?

I have a service with a timer in the background. This timer executes a certain task after 20 seconds pass. I want the same timer to execute another task, but in a different amount of seconds. This would be easy by launching both services at the same time, but I am trying to learn how I can do it this other way.
I tried this, but it isn't showing up:
cdt = new CountDownTimer(20000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
Log.v(TAG, /*"Time remaining " +*/ (millisUntilFinished / 1000) + " seconds left");
if(millisUntilFinished / 10000 == 0){ //TEN SECONDS
Log.v(TAG, (millisUntilFinished % 1000) + " seconds left");
}
}
#Override
public void onFinish() {
Log.v(TAG, "Finished");
Now, I should be getting two different log messages at ten seconds. Instead, I only get one. Here is my logCat:
The arrow indicates where there should have been another log message.
I am lost. I would really appreciate any feedback (positive or negative)! Thank you so much for all of your help.
As you said yourself, you could launch both services at the same time.
Or inside the first service, you could pass an Intent with some parameters to inform the new amount of time and then call startService().
Intent it = new Intent(getApplicationContext(), YourService.class);
it.putExtra("Time", timeInMillis);
startService(it);
I mean, modify your Service to get an extra from the calling Intent, something like this:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
long time = intent.getLongExtra("Time",0);
// Do your ticking here, based on that variable.
}
//...
}
Edit: Let's say you want to make your timer run first at 5 seconds, then at 10, 15, and so on.
Once you finish your timer, you could pass the Intent to the new Service/Timer adding the seconds you want. Like:
it.putExtra("Time", timeInMillis + 5000);
Use this type.
cdt = new CountDownTimer(10000, 1000) { //finished on 10 Seconds
#Override
public void onTick(long millisUntilFinished) {
Log.v(TAG, /*"Time remaining " +*/ (millisUntilFinished / 1000) + " seconds left");
}
#Override
public void onFinish() {
Log.v(TAG, "First 10 Seconds Finished");
LoadNextCountdown(); // call the Next Countdown method
}
}
.start();
//Method for Next Countdown
public void LoadNextCountdown()
{
cdt2=new CountDownTimer(10000,1000) { //finished on 10 Seconds
#Override
public void onTick ( long millisUntilFinished){
Log.v(TAG, /*"Time remaining " +*/ (millisUntilFinished / 1000) + " seconds left");
}
#Override
public void onFinish () {
Log.v(TAG, "Next 10 Seconds Finished");
}
} .start();
}
Happy Coding :)
Your log is not displaying because:
if(millisUntilFinished / 10000 == 0){ //TEN SECONDS
Log.v(TAG, (millisUntilFinished % 1000) + " seconds left");
}
you want it to display when you have 10000 millisUntilFinished but 10000/10000 = 1 not 0.
it should be:
if(millisUntilFinished / 10000 == 1) || if(millisUntilFinished % 10000 == 0)
or simply:
if(millisUntilFinished == 10000)

Categories

Resources