So I'm trying to write a stopwatch app that displays time in milliseconds, but for some reason it won't work. Basically I have just a togglebutton that, after being pressed, starts printing the milliseconds from the start time to the current time... In the simulator though, the app locks up. What's wrong?
public class testing extends Activity {
/** Called when the activity is first created. */
Button start,stop;
long init,now,time;
TextView display;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
display = (TextView) findViewById(R.id.chronometer1);
final ToggleButton passTog = (ToggleButton) findViewById(R.id.onoff);
passTog.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
init=System.currentTimeMillis();
while(passTog.isChecked())
{
now=System.currentTimeMillis();
time=now-init;
display.setText("t: " + time);
}
}
});
}
}
You definitely should not run a busy loop like you are doing inside the OnClickListener. That's why the app locks up. You need to let the rest of the system have its say. Also, it doesn't make sense to update the display more than once every 30 milliseconds or so, since that's about the fastest that the human eye can track. Also, you might want to suspend your timer when the activity is paused. Here's a version that does all that:
public class testing extends Activity {
/** Called when the activity is first created. */
Button start,stop;
long init,now,time,paused;
TextView display;
Handler handler;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler = new Handler();
setContentView(R.layout.test);
display = (TextView) findViewById(R.id.chronometer1);
final ToggleButton passTog = (ToggleButton) findViewById(R.id.onoff);
final Runnable updater = new Runnable() {
#Override
public void run() {
if (passTog.isChecked()) {
now=System.currentTimeMillis();
time=now-init;
display.setText("t: " + time);
handler.postDelayed(this, 30);
}
}
};
passTog.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
init = System.currentTimeMillis();
handler.post(updater);
}
});
}
#Override
protected void onPause() {
super.onPause();
paused = System.currentTimeMillis();
}
#Override
protected void onResume() {
super.onResume();
init += System.currentTimeMillis() - paused;
}
}
You put the setText() method in your onClick(), so will you click the button every second?
Its not even a thread!
Try the onTick() method of CountDownTimer class instead.
Related
I have found numerous examples of how to pause a countdowntimer in Android, but each of these examples utilises more than 1 button (pause, resume and cancel).
I want to have one button that when I press it the timer starts, then when I press it again it pauses (cancelling the original timer, capturing the timer value) and resumes when clicked again (taking the captured time from the pause to start off a new counterdowntimer).
Does anyone have an example of how to achieve this? I have tried if else loops in the onClick listener of the button. I have a very crude semi-working example;
if (gameOn == 1) {
if((clkOnTimerBtn % 2)==0) {
isPaused = true; // PAUSE COUNTDOWN TIMER
resumeCountDownTimer(view, "pause");
} else { // RESUME COUNTDOWN TIMER
resumeCountDownTimer(view, "resume");
}
The problem with the above is that this is carried out in the button onclick listener, so if a new CountDownTimer is created inside my resumeCountDownTimer its not possible to access the timer later on to cancel it (pause). I have also tried looking for a way to cancel all countdowntimers, messy if I could, but I couldn't find any examples or references to doing so as this would at least get the desired behaviour even if it isn't the most elegant way.
If I understood you correctly, something like this should work.
public class MainActivity extends AppCompatActivity {
CountDownTimer countDownTimer;
long duration = 100000; //This is the initial time,
long millisecondsLeft = 100000; // This is the time left. At the start it equales the duration.
boolean isCountDownTimerActive = false;
Button startButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start = (Button) findViewById(R.id.startStop);
final TextView timeLeft = (TextView) findViewById(R.id.timeLeft);
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (isCountDownTimerActive) {
if (countDownTimer != null)
countDownTimer.cancel();
isCountDownTimerActive = false;
} else {
countDownTimer = new CountDownTimer(millisecondsLeft, 1000) {
#Override
public void onTick(long l) {
millisecondsLeft = l;
timeLeft.setText(" " + l);
}
#Override
public void onFinish() {
}
};
isCountDownTimerActive = true;
countDownTimer.start();
}
}
});
}
}
I'm trying to do some example about countdown timer using Button and set OnclickListener for that Button. My Default value is 10 and it will be decrease each second, how can i reset my value back to 10?
CountDownTimer cannot be restarted, it can only be used once. You either have to create your own count down class that can handle being restarted, or just create a new instance of your CountDownTimer and cancel the old instance.
See the example code below where we have a CountDownTimer that counts down for 10 seconds in 1 second intervals, a Button that resets the timer when clicked (by cancelling the current timer and starting a new one), and a TextView that displays the time left in the current timer.
public class YourActivity extends Activity {
private CountDownTimer countDownTimer;
private TextView timerDisplayTextView;
private static final long TEN_SECONDS = TimeUnit.SECONDS.toMillis(10);
private static final long COUNTDOWN_INTERVAL = TimeUnit.SECONDS.toMillis(1);
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Button myButton; // initialized here
// timerDisplayTextView initialized here
myButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
countDownTimer.cancel();
countDownTimer = getNewCountDownTimer(TEN_SECONDS);
countDownTimer.start();
showTimeInTextView(TEN_SECONDS);
}
});
countDownTimer = getNewCountDownTimer(TEN_SECONDS);
countDownTimer.start();
}
#Override
protected void onDestroy() {
super.onDestroy();
countDownTimer.cancel();
}
private void showTimeInTextView(long millisecondsLeft) {
timerDisplayTextView.setText(TimeUnit.MILLISECONDS.toSeconds(millisecondsLeft) + " seconds left");
}
private CountDownTimer getNewCountDownTimer(long length) {
return new CountDownTimer(length, COUNTDOWN_INTERVAL) {
#Override
public void onTick(long millisUntilFinished) {
showTimeInTextView(millisUntilFinished);
}
#Override
public void onFinish() {
}
};
}
}
I am working on a simple game where the user is timed to answer a question.
After each correct question the user's time is reduced.
Right now, the user starts with a time of 10s.
How to make my countDownTimer reduces the amount of time with let say 0.8 after each correct answer.
I have to mention that my timer adjusts a progress bar as well.
This is my code now:
...
private ProgressBar mProgressBar;
private CountDownTimer mCountDownTimer;
private long timer_length = 10*1000;
private long timer_interval = 500;
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mProgressBar = (ProgressBar)findViewById(R.id.progressBar);
mTrueBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//is the user right? if pressing True button
if(isMathProblemTrue == 1){
//user is correct
Toast.makeText(MainActivity.this,"Correct!",Toast.LENGTH_SHORT).show();
generateMathProblem();
mCountDownTimer.cancel();
createNStartTimer();
}else{
//user is incorrect
transferUserToStartScreen();
mCountDownTimer.cancel(); // cancel
}
}
});
}
private void createNStartTimer() {
mCountDownTimer = new CountDownTimer(timer_length,timer_interval) {
#Override
public void onTick(long millisUntilFinished) {
int progress = (int) (millisUntilFinished/100);
mProgressBar.setProgress(progress);
}
#Override
public void onFinish() {
mProgressBar.setProgress(0);
transferUserToStartScreen();
}
}.start();
}
I'm a begginer in android programming and trying to improve my knowledge. I want to make an app that is a regressive chronometer, like this: I insert the seconds I want in a text view named "seconds", then press a button and the app counts down the seconds (for example: 50, 49, 48, ..., 0) in another text view called, let's say... "timeRemaining".
How this can be done? I have read some other questions here, but to be honest, I could not understand them...
Well, I managed to do something here, The countdown is working, but only if I set the time directly on the code. I cannot find a way to implement the conversion of the number (text) entered in the text view to LONG and then use this value as the time to countdown.
There is no error when debugging, but when the simulator is about to run the app and opens the activity, it stop with the message "Unfortunately, app has stopped"
Here's the code, if anyone can help me finding what I'm missing, I'll be glad!
Thank you all!
public class cronometro extends Activity implements View.OnClickListener {
Long tempo3 = Long.parseLong(findViewById(R.id.tempo).toString());
private CountDownTimer countDownTimer;
private boolean timerStarted = false;
private Button buttonStart;
public TextView textView;
private final long startTime = tempo3 * 1000;
private final long interval = 1 * 1000;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cronometro);
buttonStart = (Button) this.findViewById(R.id.button);
buttonStart.setOnClickListener(this);
textView = (TextView) this.findViewById(R.id.textView);
countDownTimer = new CountDownTimerActivity(startTime, interval);
textView.setText(textView.getText() + String.valueOf(startTime/1000));
}
#Override
public void onClick(View v) {
if (!timerStarted) {
countDownTimer.start();
timerStarted = true;
buttonStart.setText("PARAR");
} else {
countDownTimer.cancel();
timerStarted = false;
buttonStart.setText("REINICIAR");
}
}
public class CountDownTimerActivity extends CountDownTimer {
public CountDownTimerActivity(long startTime, long interval) {
super(startTime, interval);
}
#Override
public void onFinish() {
textView.setText("tempo esgotado!");
}
#Override
public void onTick(long millisUntilFinished) {
textView.setText("" + millisUntilFinished/1000);
}
}
}
i creating for stopwatch with start,stop i use following code it started but not stop. please help me.
my code:
public class StopWatch2 extends Activity implements Runnable{
// text view influenced by the Thread
private TextView threadModifiedText;
int time=0;
Button b1,b2,b3;
/** Called when the activity is first created. */
Thread currentThread = new Thread(this);
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.stopwatch);
b1=(Button)findViewById(R.id.button1);
b2=(Button)findViewById(R.id.button2);
b3=(Button)findViewById(R.id.button3);
threadModifiedText = (TextView) findViewById(R.id.textView1);
b1.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
currentThread.start();
}
});
b2.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
currentThread.stop();
}
});
}
//Method you must override to control what the Thread is doing
#Override
public void run(){
try {
while(true){
currentThread.sleep(1000, 0);
threadHandler.sendEmptyMessage(0);
}
// signaling things to the outside world goes like this
} catch (InterruptedException e) {
}
}
private Handler threadHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
time++;
threadModifiedText.setText(""+time);
}
};
}
I think You should use a class level variable boolean shouldRun = true ;
in your run() method while should be used like this way
while(shouldRun)
{
//implementation
}
and in your b2.onClickListener() change shouldRun = false;
Edit:
For suspend and resume you can change the value of shouldRun to shouldRun = true; in the listener for resume button. Remember that when you stop the updates you should reset the time also. and in suspend the time should be remain same.
I implemented stopwatch for rotational puzzles solving time measurements and I have approached it somewhat differently.
For time measurements I use Handler object that triggers after DISPLAY_UPDATE_TIMEOUT. It is time after which you update display about time elapsed.
To start counting I use:
mLastStartTimestamp = System.currentTimeMillis();
mRepetitiveTimeoutHandler.postDelayed(processWatchTimer, DISPLAY_UPDATE_TIMEOUT);
and to stop it
mRepetitiveTimeoutHandler.removeCallbacks(processWatchTimer);
mStartStopElapsed = System.currentTimeMillis() - mLastStartTimestamp ;
updateTimeDisplay();
On each trigger of the handler I do the following:
private Runnable processWatchTimer = new Runnable()
{
public void run()
{
mRepetitiveTimeoutHandler.postDelayed(processWatchTimer, DISPLAY_UPDATE_TIMEOUT);
updateTimeDisplay();
}
};