Reputation: 1
I am trying to create a timer with a circle progress bar. I have found a good example to begin with http://www.androidtutorialshub.com/android-count-down-timer-tutorial/. This example has the looks that I need but I want to add pause and resume functionality to it. So, I do have the pause and resume working, however after I click "Pause" and then "Resume" the progress bar starts from scratch for a spit of a second and then resumes from the position pause was set on(which is the goal). My guess is that the progress bar is set to 100% somewhere and then replaced with pause position, but I cant find the part where that might happen.
Modified mainActivity code:
public class MainActivity extends AppCompatActivity {
private long timeCountInMilliSeconds = 1 * 60000;
long startTime;
long difference;
long difference1;
private enum TimerStatus {
STARTED,
STOPPED,
}
private TimerStatus timerStatus = TimerStatus.STOPPED;
private ProgressBar progressBarCircle;
private EditText editTextMinute;
private TextView textViewTime;
private ImageView imageViewReset;
private ImageView imageViewStartStop;
private CountDownTimer countDownTimer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progressBarCircle = (ProgressBar) findViewById(R.id.progressBarCircle);
editTextMinute = (EditText) findViewById(R.id.editTextMinute);
textViewTime = (TextView) findViewById(R.id.textViewTime);
imageViewReset = (ImageView) findViewById(R.id.imageViewReset);
imageViewStartStop = (ImageView) findViewById(R.id.imageViewStartStop);
imageViewReset.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
reset();
}
});
imageViewStartStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
pauseResume();
}
});
}
private void reset() {
stopCountDownTimer();
restartCountDownTimer();
}
private void pauseResume() {
if (timerStatus == TimerStatus.STOPPED) {
timeCountInMilliSeconds = 1 * 50000;
// setProgressBarValues(timeCountInMilliSeconds);
progressBarCircle.setMax((int) (timeCountInMilliSeconds) / 1000);
progressBarCircle.setProgress((int) (timeCountInMilliSeconds) / 1000);
imageViewReset.setVisibility(View.VISIBLE);
imageViewStartStop.setImageResource(R.drawable.icon_stop);
editTextMinute.setEnabled(false);
timerStatus = TimerStatus.STARTED;
startCountDownTimer();
startTime = System.currentTimeMillis();
} else {
imageViewReset.setVisibility(View.GONE);
imageViewStartStop.setImageResource(R.drawable.icon_start);
editTextMinute.setEnabled(true);
timerStatus = TimerStatus.STOPPED;
stopCountDownTimer();
if(difference == 0) {
difference = System.currentTimeMillis() - startTime;
}
else{
difference1 = System.currentTimeMillis() - startTime;
difference += difference1;}
}
}
private void startCountDownTimer() {
countDownTimer = new CountDownTimer(timeCountInMilliSeconds - difference, 1000) {
@Override
public void onTick(long millisUntilFinished) {
textViewTime.setText(hmsTimeFormatter(millisUntilFinished));
progressBarCircle.setProgress((int) (millisUntilFinished / 1000));
}
@Override
public void onFinish() {
textViewTime.setText(hmsTimeFormatter(timeCountInMilliSeconds - difference));
// setProgressBarValues(timeCountInMilliSeconds - difference);
progressBarCircle.setMax((int) (timeCountInMilliSeconds - difference) / 1000);
progressBarCircle.setProgress((int) (timeCountInMilliSeconds - difference) / 1000);
imageViewReset.setVisibility(View.GONE);
imageViewStartStop.setImageResource(R.drawable.icon_start);
editTextMinute.setEnabled(true);
timerStatus = TimerStatus.STOPPED;
}
}.start();
countDownTimer.start();
}
private void restartCountDownTimer() {
difference = 0;
difference1 = 0;
countDownTimer = new CountDownTimer(timeCountInMilliSeconds, 1000) {
@Override
public void onTick(long millisUntilFinished) {
textViewTime.setText(hmsTimeFormatter(millisUntilFinished));
progressBarCircle.setProgress((int) (millisUntilFinished / 1000));
}
@Override
public void onFinish() {
textViewTime.setText(hmsTimeFormatter(timeCountInMilliSeconds));
// setProgressBarValues(timeCountInMilliSeconds);
progressBarCircle.setMax((int) (timeCountInMilliSeconds) / 1000);
progressBarCircle.setProgress((int) (timeCountInMilliSeconds) / 1000);
imageViewReset.setVisibility(View.GONE);
imageViewStartStop.setImageResource(R.drawable.icon_start);
editTextMinute.setEnabled(true);
timerStatus = TimerStatus.STOPPED;
}
}.start();
countDownTimer.start();
}
private void stopCountDownTimer() {
countDownTimer.cancel();
}
private String hmsTimeFormatter(long milliSeconds) {
String hms = String.format("%02d:%02d:%02d",
TimeUnit.MILLISECONDS.toHours(milliSeconds),
TimeUnit.MILLISECONDS.toMinutes(milliSeconds) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(milliSeconds)),
TimeUnit.MILLISECONDS.toSeconds(milliSeconds) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(milliSeconds)));
return hms;
}
}
The XML file is the same as in the link provided above(the link to the sample code).
Any help would be very much appreciated.
Upvotes: 0
Views: 225
Reputation: 416
Probably the error is in your pauseResume
. There you say progressBarCircle.setProgress((int) (timeCountInMilliSeconds) / 1000);
. This sets the current progress to the specified value. In your case this means the same value as you max value. I think you should move the whole block up into the onCreate
method.
timeCountInMilliSeconds = 1 * 50000;
progressBarCircle.setMax((int) (timeCountInMilliSeconds) / 1000);
progressBarCircle.setProgress((int) (timeCountInMilliSeconds) / 1000);
It should be enough to initialize these values once at the beginning.
[Edit]
The behavior seems good to me. Let's say you press pause if the timer is at 47sec, now depends on your timing, the timer can be paused at 999 milliseconds or 001 msec. (to point edge cases). In the first case you have to wait "nearly" one second, to be precise 999 msec., until the timer switches visibly the state. In the seconds case it feels like the app responds directly, because you only have to wait 001 msec. If you want to fix that, normalize your difference
value like so:
private void pauseResume() {
if (timerStatus == TimerStatus.STOPPED) {
...
} else {
...
difference += (((int) (System.currentTimeMillis() - startTime) / 1000) + 1) * 1000;
}
}
I also removed the usless difference1
variable.
Another improvement I made, I've removed the if else
statement, because it is also useless.
You can also remove the + 1
to always wait 1sec. before you see something visual.
Upvotes: 0