I made a CountDownTimer code, i would like to CountDownTimer restart when countdown finished even if app is closed, but it only restart if app running or when app is re-launched. So if i close the app when countdown is 00:10 (min:sec) and reopen the app after 30 sec, the counter should be 00:40, but it starts from 1 minute... But if i close app in 00:40 and reopen after 10 sec, it starts from 00:30 so its good, but the problem only with restart from 1 min when app closed.... can somebody help me?
My code:
package com.example.countdown_implement;
import android.content.SharedPreferences;
import android.os.CountDownTimer;
import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Locale;
public class MainActivity extends AppCompatActivity {
private static final long START_TIME_IN_MILLIS = 60000;
private TextView mTextViewCountDown;
private CountDownTimer mCountDownTimer;
private boolean mTimerRunning;
private long mTimeLeftInMillis;
private long mEndTime;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextViewCountDown = findViewById(R.id.text_view_countdown);
}
private void startTimer() {
mEndTime = System.currentTimeMillis() + mTimeLeftInMillis;
mCountDownTimer = new CountDownTimer(mTimeLeftInMillis, 1000) {
@Override
public void onTick(long millisUntilFinished) {
mTimeLeftInMillis = millisUntilFinished;
updateCountDownText();
}
@Override
public void onFinish() {
//mTimerRunning = false;
//updateButtons();
updateCountDownText();
resetTimer();
startTimer();
}
}.start();
//mTimerRunning = true;
}
private void resetTimer() {
mTimeLeftInMillis = START_TIME_IN_MILLIS;
updateCountDownText();
}
private void updateCountDownText() {
int minutes = (int) (mTimeLeftInMillis / 1000) / 60;
int seconds = (int) (mTimeLeftInMillis / 1000) % 60;
String timeLeftFormatted = String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds);
mTextViewCountDown.setText(timeLeftFormatted);
}
@Override
protected void onStop() {
super.onStop();
SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putLong("millisLeft", mTimeLeftInMillis);
editor.putBoolean("timerRunning", mTimerRunning);
editor.putLong("endTime", mEndTime);
editor.apply();
}
@Override
protected void onStart() {
super.onStart();
SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
mTimeLeftInMillis = prefs.getLong("millisLeft", START_TIME_IN_MILLIS);
mTimerRunning = prefs.getBoolean("timerRunning", false);
mEndTime = prefs.getLong("endTime", 0);
mTimeLeftInMillis = mEndTime - System.currentTimeMillis();
updateCountDownText();
startTimer();
if (mTimeLeftInMillis < 0) {
updateCountDownText();
startTimer();
}
}
}
UPDATED
Below is your code converted into a code snippet for a CountdownTimer which will keep working even when the app is closed, pushed to background or restarted.
set START_TIME_IN_MILLIS
as the Timer start time, in the following example it is set to 15 seconds.
import android.content.SharedPreferences;
import android.os.CountDownTimer;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Locale;
public class MainActivity2 extends AppCompatActivity {
private static final long START_TIME_IN_MILLIS = 15000;
private TextView mTextViewCountDown;
private CountDownTimer mCountDownTimer;
private boolean mTimerRunning;
private long mTimeLeftInMillis;
private long mEndTime;
private long remainingTimeInMillis;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new);
mTextViewCountDown = findViewById(R.id.tv);
}
private void startTimer() {
mCountDownTimer = new CountDownTimer(remainingTimeInMillis, 1000) {
@Override
public void onTick(long millisUntilFinished) {
remainingTimeInMillis = millisUntilFinished;
mTimeLeftInMillis = millisUntilFinished;
updateCountDownText();
}
@Override
public void onFinish() {
//mTimerRunning = false;
//updateButtons();
updateCountDownText();
resetTimer();
startTimer();
}
}.start();
//mTimerRunning = true;
}
private void resetTimer() {
remainingTimeInMillis = START_TIME_IN_MILLIS;
updateCountDownText();
}
private void updateCountDownText() {
int minutes = (int) (remainingTimeInMillis / 1000) / 60;
int seconds = (int) (remainingTimeInMillis / 1000) % 60;
String timeLeftFormatted = String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds);
mTextViewCountDown.setText(timeLeftFormatted);
}
@Override
protected void onStop() {
super.onStop();
SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putLong("millisLeft", mTimeLeftInMillis);
editor.putBoolean("timerRunning", mTimerRunning);
editor.putLong("endTime", System.currentTimeMillis());
editor.apply();
}
@Override
protected void onStart() {
super.onStart();
SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
mTimeLeftInMillis = prefs.getLong("millisLeft", START_TIME_IN_MILLIS);
mTimerRunning = prefs.getBoolean("timerRunning", false);
mEndTime = prefs.getLong("endTime", 0);
if (mEndTime == 0L) {
remainingTimeInMillis = (mTimeLeftInMillis);
} else {
Long timeDiff = (mEndTime - System.currentTimeMillis());
//to convert into positive number
timeDiff = Math.abs(timeDiff);
long timeDiffInSeconds = (timeDiff / 1000) % 60;
long timeDiffInMillis = timeDiffInSeconds * 1000;
Long timeDiffInMillisPlusTimerRemaining = remainingTimeInMillis = mTimeLeftInMillis - timeDiffInMillis;
if (timeDiffInMillisPlusTimerRemaining < 0) {
timeDiffInMillisPlusTimerRemaining = Math.abs(timeDiffInMillisPlusTimerRemaining);
remainingTimeInMillis = START_TIME_IN_MILLIS - timeDiffInMillisPlusTimerRemaining;
}
}
updateCountDownText();
startTimer();
}
}