CountDownTimer runs in old Activity when switching Activities - android

I have a CountDownTimer, which needs to run all the time. There are 2 Activities (A and B). Activity A has the CountDownTimer, which updates a TextView inside it. When I switch to B, the CountDownTimer still runs (it is the desired behavoir), but when I switch back to A, there seems to be an old and a new A. The timer does not update a TextView inside of the "new" A. It is started only once when A is first visited. Any ideas of how to solve this problem? Maybe put the timer somewhere else?
Edit: Some code:
private void prepareTimer() {
// TODO: DOES NOT WORK YET! (switching activities -> runs in old activity)
textTime = (TextView) findViewById(R.id.text_time); // is a field
if (!timerRunning) {
timerRunning = true;
int duration = 60000;
timer = new CountDownTimer(duration, 1000) {
public void onTick(long millisUntilFinished) {
long minsLeft = (long) Math.floor((double) millisUntilFinished / (double) Constants.ONE_MINUTE) + 1;
textTime.setText(minsLeft + " Min.");
}
public void onFinish() {
textTime.setText("done!");
}
};
timer.start();
}
}

CDT is running in its own separate thread. The TextView reference you are trying to access, in that CDT is no longer usable (because your activity A was no longer visible while you was in B) try to create new reference that TextView when you return to A. The CDT thread was still running regardless you have moved from A to B or viceversa. I hope this will help. Make sure you do changes in UI thread. ;)
Edit:
private void prepareTimer() {
// TODO: DOES NOT WORK YET! (switching activities -> runs in old activity)
textTime = (TextView) findViewById(R.id.text_time); // is a field
if (!timerRunning) {
timerRunning = true;
int duration = 60000;
timer = new CountDownTimer(duration, 1000) {
public void onTick(long millisUntilFinished) {
long minsLeft = (long) Math.floor((double) millisUntilFinished / (double) Constants.ONE_MINUTE) + 1;
textTime.setText(minsLeft + " Min.");
}
public void onFinish() {
textTime.setText("done!");
}
};
timer.start();
}
else
{
textTime = (TextView) findViewById(R.id.text_time);
}
}

Related

countDowntimer not Resetting for a new Value and shows the old value always

I am trying to show a countDownTimer in my activity. the value I am using in the countDowntimer is coming from a recyclerview of another activity using bundle. when I click one of the recyclerview time for the first time, the countDownTimer shows the time running perfectly. but when I select another time, the old instance continues to run. I have implemented the cancel and onFinish() methods to but they are not working as I want. I searched everywhere but everyone suggested about cancel and onFinish() methods. I am unable to find a solution now.
public void getData() {
if(countDownTimer!=null){
countDownTimer.cancel();
}
if (replaceTime != null) {
time = Integer.parseInt(replaceTime);
} else
Toast.makeText(FullTimerActivity.this, "",
Toast.LENGTH_LONG).show();
totalTimeCountInMilliseconds = time;
timeBlinkInMilliseconds = 30 * 1000;
countDownTimer = new CountDownTimer(totalTimeCountInMilliseconds, 500) {
#Override
public void onTick(long leftTimeInMilliseconds) {
long seconds = leftTimeInMilliseconds / 1000;
if (leftTimeInMilliseconds < timeBlinkInMilliseconds) {
if (blink) {
// mTextField.setVisibility(View.VISIBLE);
// if blink is true, textview will be visible
} else {
// mTextField.setVisibility(View.INVISIBLE);
}
blink = !blink;
}
String a = String.format("%02d", seconds / 60) + ":" + String.format("%02d", seconds % 60);
textView.setText(a);
}
#Override
public void onFinish() {
Toast.makeText(FullTimerActivity.this, "Finished", Toast.LENGTH_SHORT).show();
}
}.start();
}
thank you in advance.
In onFinish() also set the text to TextView like below
textView.setText("0");

Cannot get pause and resume functionality to work with progress bar

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

Restart countodown timer with different timer android

I am making a repeating countdown timer app.I require the countdown timer to restart with a different time.I am using a global variable in the constructor of the countdown timer.But the problem is that it always restarts from the starting of the first given interval.
public void chance(final int tota, final int cur, final int exercise,int pass,int flag)
{
Log.i("inside value","reached");
a = new CountDownTimer((tempmilliseconds) * 1000 + 100, 1000) {
#Override
public void onTick(long millisUntilFinished) {
tempmilliseconds = (int) millisUntilFinished / 1000;
Log.i("inside value",Integer.toString(tempmilliseconds));
updatetimer(millisUntilFinished);
}
#Override
public void onFinish() {
mtext.setText("0:00");
cancel();
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
currentcompleted++;
if (on == 0) {
on = 1;
int exercis = MainActivity.restmint * 60 + MainActivity.restsec;
tempmilliseconds=exercis;
chance(tota, curr + 1, exercis, 0, 0);
} else {
on = 0;
int exercis = MainActivity.exermint * 60 + MainActivity.exersec;
tempmilliseconds=exercis;
chance(tota, curr + 1, exercis, 0, 0);
}
}
}, 1000);
}
};
a.start();
}
Below is the code for resume operations:
public void resume(View view) {
Button mytext=(Button) findViewById(R.id.resume);
if( mytext.getText().toString()=="Pause") {
mytext.setText("Play");
a.cancel();
}
else {
mytext.setText("Pause");
Log.i("Value of temp",Integer.toString(tempmilliseconds));
a.start();
}
}
The timer is stopping but when started in the resume function restarts with the original time and not specified by tempmilliseconds.Note tempmilliseconds is updated every seconds.
Any help/snippets/suggestions is appreciated.Thank you!
A CountDownTimer will not allow itself to be disturbed in any case. It will remember the time it was born with till someone kills it.
If you look at its documentation you'd see that it directly inherits from Object class and has only four methods: start(), cancel(), onFinish() (abstract) and onTick() (abstract). Thats pretty much it. So, you basically are left with no choice but to call cancel() and then re-initialise the timer. Or, you can extend the CountDownTimer class and encapsulate this under the hood.
In either case the cost of cancelling ad re-initialising may get tedious.

Keep Timer Ticking in Background

How can I keep the value of my timer resuming after going to another activity , my problem is that it's set to default if I switched to another activity I thought of using sharedpreference but it won't help because I need it to keep decrementing in the background.
public void reset()
{
countDownTimer.cancel();
}
private void setTimer() {
int time = 5;
if(countDownTimer==null)
{
totalTimeCountInMilliseconds = 60 * time * 1000;
}
else
{
reset();
totalTimeCountInMilliseconds = 60 * time * 1000;
}
}
private void startTimer() {
countDownTimer = new CountDownTimer(totalTimeCountInMilliseconds, 500) {
// 500 means, onTick function will be called at every 500
// milliseconds
//#Override
public void onTick(long leftTimeInMilliseconds) {
seconds = leftTimeInMilliseconds / 1000;
textViewShowTime.setText(String.format("%02d", seconds / 60)
+ ":" + String.format("%02d", seconds % 60));
// format the textview to show the easily readable format
}
#Override
public void onFinish() {
// this function will be called when the timecount is finished
textViewShowTime.setText("Time up!");
textViewShowTime.setVisibility(View.VISIBLE);
}
}.start();
}
You should stop your CountDownTimer in onPause and restart in onResume, your textViewShowTime might not be valid while your activity is in background.
If you need to call some code every 500ms no matter what activity you are in, then consider using AlarmManager.

Android countdown timer wont accept variable

i just started to learn creating android apps. I wanted to create a simple count down timer that takes a value from a edittext but countdown timer does not seem to run.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
countDownTxt = (TextView) findViewById(R.id.countDownView);
intervalTxt = (TextView) findViewById(R.id.intervalText);
findViewById(R.id.startBN).setOnClickListener(
new View.OnClickListener() {
public void onClick(View v) {
int testInt = 30;
//countDownTxt.setText(intervalTxt.getText());
int interval = Integer.parseInt(intervalTxt.getText().toString());
Log.d("buttonpressed", "interval for countdown is " + interval);
cdt = new CountDownTimer(Integer.parseInt(intervalTxt.getText().toString()), 1000) {
public void onTick(long millisUntilFinished) {
Log.d("counttimer1", "haha1");
countDownTxt.setText(""+ millisUntilFinished / 1000);
}
public void onFinish() {
cancel();
}
}.start();
}
}
);
}
In particular, this program works only if i enter a numerical value such as 30000 in the 1st parameter of the CountDownTimer "cdt = new CountDownTimer(testInt, 1000)"
Can someone enlighten me please? Thank you!
"Doesn't work" how? You should post the error message you're getting or other symptoms of "doesn't work."
What's probably happening is CountDownTimer accepts only long values as the first parameter of its constructor. Not int values.
Change int testInt = 30 to long testLong = 10000.0f and see what happens.
The first parameter means milliseconds, by the way, so "30" isn't really going to get you much in the first place.
onTick() method is called in a separate Thread. But you don't have right to use setText() method outside the GUI Thread.
You must use a Handler object or Activity.postOnUiThread() method to execute something in the GUI Thread :
cdt = new CountDownTimer(Integer.parseInt(intervalTxt.getText().toString()), 1000) {
public void onTick(long millisUntilFinished) {
Log.d("counttimer1", "haha1");
runOnUiThread(new Runnable() {
#Override
public void run() {
countDownTxt.setText("" + millisUntilFinished / 1000);
}
});
countDownTxt.setText(""+ millisUntilFinished / 1000);
}
public void onFinish() {
cancel();
}
}.start();
For more informations, read http://developer.android.com/guide/components/processes-and-threads.html#Threads

Categories

Resources