Stop a stopwatch in Android

1.5k Views Asked by At

I've made a custom stop watch which showing hours:minuted:seconds.Controls are given by START and STOP buttons.But, there is a problem when stopping the stopwatch.It didn't stop when the STOP button is clicked. Anybody please suggest me the right solution.

    package com.example.mystopwatch;


import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;


public class StopwatchActivity extends Activity {
private TextView textViewTimer;
private Button BtnStart,BtnStop;
private Handler mHandler = new Handler();
private long startTime;
private long elapsedTime;
private final int REFRESH_RATE = 100;
private String hours,minutes,seconds,milliseconds;
private long secs,mins,hrs,msecs;
private boolean stopped = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_stopwatch);
    BtnStart=(Button)findViewById(R.id.startbtn);
    BtnStop=(Button)findViewById(R.id.stopbtn);
    BtnStart.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
             Runnable startTimer1 = new Runnable() 
            { 
                public void run() 
                {
                    elapsedTime = System.currentTimeMillis() - startTime; updateTimer(elapsedTime);
                    mHandler.postDelayed(this,REFRESH_RATE); 
                    }


                };
             if(stopped)
             {
                 startTime = System.currentTimeMillis() - elapsedTime;
                 } 
             else
             { 
                 startTime = System.currentTimeMillis(); 
                 } 
             mHandler.removeCallbacks(startTimer1);
             mHandler.postDelayed(startTimer1, 0);


        }
                });
    BtnStop.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
             Runnable startTimer2 = new Runnable() 
                { 
                    public void run() 
                    {
                        elapsedTime = System.currentTimeMillis() - startTime; updateTimer(elapsedTime);
                        mHandler.postDelayed(this,REFRESH_RATE); 
                        }


                    };

            mHandler.removeCallbacks(startTimer2);
            stopped = true;

        }
    });

}   
private void updateTimer(long time) {
    // TODO Auto-generated method stub

        secs = (long)(time/1000); 
    mins = (long)((time/1000)/60);
    hrs = (long)(((time/1000)/60)/60); 
    secs = secs % 60; 
    seconds=String.valueOf(secs);
    if(secs == 0)
    { 
        seconds = "00";

    } 
    if(secs <10 && secs > 0)
    { 
        seconds = "0"+seconds; 
        }
    mins = mins % 60;
    minutes=String.valueOf(mins);
    if(mins == 0){ minutes = "00";
    } 
    if(mins <10 && mins > 0)
    {
        minutes = "0"+minutes;
        }
    hours=String.valueOf(hrs);
    if(hrs == 0)
    { 
        hours = "00";
        }
    if(hrs <10 && hrs > 0)
    {
        hours = "0"+hours;
        }
     milliseconds = String.valueOf((long)time);
     if(milliseconds.length()==2)
     {
         milliseconds = "0"+milliseconds;
         }
     if(milliseconds.length()<=1)
     { milliseconds = "00";
     } 
     milliseconds = milliseconds.substring(milliseconds.length()-3, milliseconds.length()-2); 
     ((TextView)findViewById(R.id.timertxt)).setText(hours + ":" + minutes + ":" + seconds);
     }
    }
3

There are 3 best solutions below

0
On

It can not stop since you don't check boolean stopped in your run method. Move it inside :

public void run() {
    elapsedTime = System.currentTimeMillis() - startTime;
    updateTimer(elapsedTime);
    if(!stopped) {
        mHandler.postDelayed(this, REFRESH_RATE);
    }
}

and also consider declaring stopped as volatile as per suggestion in the comments.

0
On

there is whole task to start and stop , stopwatch just call :-- handler.sendEmptyMessage(MSG_STOP_TIMER); to stop stopwatch

Handler handler = new Handler()
{
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what) {
        case MSG_START_TIMER:
            timer.start(); //start timer

            handler.sendEmptyMessage(MSG_UPDATE_TIMER);
            break;

        case MSG_UPDATE_TIMER:
            //timerText.setText(String.format("%1$tM:%1$tS",timer.getElapsedTimeMin(),timer.getElapsedTimeSecs()));
            if ( timer.getElapsedTimeSecs() < 10)
            {
                if(timer.getElapsedTimeMin()<10){
                    timerText.setText("0" + timer.getElapsedTimeMin() + ":0" + timer.getElapsedTimeSecs());
                }else{
                    timerText.setText("" + timer.getElapsedTimeMin() + ":0" + timer.getElapsedTimeSecs());  
                }
            }
            else{
                if(timer.getElapsedTimeMin()<10){
                    timerText.setText("0" + timer.getElapsedTimeMin() + ":" + timer.getElapsedTimeSecs());
                }else{
                    timerText.setText(timer.getElapsedTimeMin()+":"+ timer.getElapsedTimeSecs());  
                }

            }
            handler.sendEmptyMessageDelayed(MSG_UPDATE_TIMER,REFRESH_RATE); //text view is updated every second,
            break;                                  //though the timer is still running
        case MSG_STOP_TIMER:
            handler.removeMessages(MSG_UPDATE_TIMER); // no more updates.
            timer.stop();//stop timer
            timerText.setText("0"+timer.getElapsedTimeMin()+":0"+ timer.getElapsedTimeSecs());
            break;

        default:
            break;
        }
    }
};
0
On

Most of the code in your BtnStop.setOnClickListener is actually useless. You define a Runnable called startTimer2, but for what purpose? You never use that Runnable except in the call to mHandler.removeCallbacks(startTimer2);. That will remove any calls that were made to it before, but since you never made any, this does not do anything.

The only thing your method does when you click the stop button is to set the boolean flag stopped to true. But there is no periodic process checking that flag. The only time you check the flag is when the START button is pressed.

As a side note, your use of REFRESH_RATE is confusing. Setting a higher number will actually result in a lower refresh rate since postDelayed takes a duration. Consider renaming the variable or adding a division.