본문 바로가기
안드로이드 자바

[Java][Android] 안드로이드 스레드, 핸들러를 이용한 스탑워치

by teamnova 2021. 2. 6.

이번 예제에서는 스레드를 이용해서 간단한 기능을 가진 스톱워치를 만들어 볼 예정입니다.

스탑워치의 기능은 시작, 일시정지, 리셋의 기능만 가진 아주 간단한 스탑워치입니다. 

 

activity_timer.xml

위에서 설명한대로, 스탑워치 뷰에는 초를 나타내는 TextView와 Start, Pause, Reset 3개의 버튼을 가지고 있습니다.

 

TimerActivity.java

public class TimerActivity extends AppCompatActivity {

    TextView textView;          // 초를 나타날 TextView

    Button start, pause, reset; // 시작, 일시정지, 리셋 버튼

    long MillisecondTime = 0L;  // 스탑워치 시작 버튼을 누르고 흐른 시간
    long StartTime = 0L;        // 스탑워치 시작 버튼 누르고 난 이후 부터의 시간
    long TimeBuff = 0L;         // 스탑워치 일시정지 버튼 눌렀을 때의 총 시간
    long UpdateTime = 0L;       // 스탑워치 일시정지 버튼 눌렀을 때의 총 시간 + 시작 버튼 누르고 난 이후 부터의 시간 = 총 시간

    Handler handler;            //

    int Seconds, Minutes, MilliSeconds;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_timer);

        // 각각의 뷰를 inflate 해준다.
        textView = (TextView)findViewById(R.id.textView);
        start = (Button)findViewById(R.id.button);
        pause = (Button)findViewById(R.id.button2);
        reset = (Button)findViewById(R.id.button3);

        handler = new Handler() ;

        // 스탑워치 시작 버튼
        start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                // SystemClock.uptimeMillis()는 디바이스를 부팅한후 부터 쉰 시간을 제외한 밀리초를 반환
                StartTime = SystemClock.uptimeMillis();
                handler.postDelayed(runnable, 0);

                // 시작 버튼 클릭 시 리셋 버튼을 비활성화 시켜준다.
                reset.setEnabled(false);

            }
        });

        // 스탑워치 일시정시 버튼
        pause.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                // 스탑워치 일시정지 버튼 눌렀을 때의 총 시간
                TimeBuff += MillisecondTime;
                
                // Runnable 객체 제거
                handler.removeCallbacks(runnable);

                // 일시정지 버튼 클릭 시 리셋 버튼을 활성화 시켜준다.
                reset.setEnabled(true);

            }
        });

        // 스탑워치 리셋 버튼
        reset.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                // 측정 시간을 모두 0으로 리셋시켜준다.
                MillisecondTime = 0L ;
                StartTime = 0L ;
                TimeBuff = 0L ;
                UpdateTime = 0L ;
                Seconds = 0 ;
                Minutes = 0 ;
                MilliSeconds = 0 ;

                // 초를 나타내는 TextView를 0초로 갱신시켜준다.
                textView.setText("00:00:00");
            }
        });

    }

    //
    public Runnable runnable = new Runnable() {

        public void run() {

            // 디바이스를 부팅한 후 부터 현재까지 시간 - 시작 버튼을 누른 시간
            MillisecondTime = SystemClock.uptimeMillis() - StartTime;

            // 스탑워치 일시정지 버튼 눌렀을 때의 총 시간 + 시작 버튼 누르고 난 이후 부터의 시간 = 총 시간
            UpdateTime = TimeBuff + MillisecondTime;

            Seconds = (int) (UpdateTime / 1000);

            Minutes = Seconds / 60;

            Seconds = Seconds % 60;

            MilliSeconds = (int) (UpdateTime % 1000);

            // TextView에 UpdateTime을 갱신해준다
            textView.setText("" + Minutes + ":"
                    + String.format("%02d", Seconds) + ":"
                    + String.format("%03d", MilliSeconds));

            handler.postDelayed(this, 0);
        }

    };
}

 

설명

필요한 변수들을 선언 및 초기화 해줍니다. (변수에 대한 설명은 주석을 참고해주세요)

각각의 뷰를 inflate 해줍니다.

 

start 버튼

// 스탑워치 시작 버튼
start.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {

        // SystemClock.uptimeMillis()는 디바이스를 부팅한후 부터 쉰 시간을 제외한 밀리초를 반환
        StartTime = SystemClock.uptimeMillis();

        // (실행할 Runnable 객체, 딜레이 시간)
        handler.postDelayed(runnable, 0);

        // 시작 버튼 클릭 시 리셋 버튼을 비활성화 시켜준다.
        reset.setEnabled(false);

    }
});

시작 버튼을 누르면 디바이스 부팅시점 부터 현재까지의 시간을 StartTime으로 받아옵니다. 

그리고 Handler의 postDelayed() 메소드를 통해 runnable을 실행시켜 줍니다. 시작 버튼을 클릭 시 바로 스탑워치가 동작해야 되기 때문에 딜레이 시간은 0으로 설정합니다.

리셋 버튼을 비활성화 시켜줍니다.

 

pause 버튼

// 스탑워치 일시정시 버튼
pause.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {

        // 스탑워치 일시정지 버튼 눌렀을 때의 총 시간
        TimeBuff += MillisecondTime;

        // Runnable 객체 제거
        handler.removeCallbacks(runnable);

        // 일시정지 버튼 클릭 시 리셋 버튼을 활성화 시켜준다.
        reset.setEnabled(true);

    }
});

일시정지 버튼을 누르면 시작 버튼을 누른 후 경과한 시간을 TimeBuff 값에 더해줍니다. 

그 후, handler에서 Runnable 객체를 제거합니다.

리셋 버튼을 활성화 시켜줍니다.

 

reset 버튼

// 스탑워치 리셋 버튼
reset.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {

        // 측정 시간을 모두 0으로 리셋시켜준다.
        MillisecondTime = 0L ;
        StartTime = 0L ;
        TimeBuff = 0L ;
        UpdateTime = 0L ;
        Seconds = 0 ;
        Minutes = 0 ;
        MilliSeconds = 0 ;

        // 초를 나타내는 TextView를 0초로 갱신시켜준다.
        textView.setText("00:00:00");
    }
});

리셋 버튼을 누르면 시간에 관련된 모든 변수를 0으로 리셋시켜줍니다.

 

Runnable 객체 선언

public Runnable runnable = new Runnable() {

    public void run() {

        // 디바이스를 부팅한 후 부터 현재까지 시간 - 시작 버튼을 누른 시간
        MillisecondTime = SystemClock.uptimeMillis() - StartTime;

        // 스탑워치 일시정지 버튼 눌렀을 때의 총 시간 + 시작 버튼 누르고 난 이후 부터의 시간 = 총 시간
        UpdateTime = TimeBuff + MillisecondTime;

        Seconds = (int) (UpdateTime / 1000);

        Minutes = Seconds / 60;

        Seconds = Seconds % 60;

        MilliSeconds = (int) (UpdateTime % 1000);

        // TextView에 UpdateTime을 갱신해준다
        textView.setText("" + Minutes + ":"
                + String.format("%02d", Seconds) + ":"
                + String.format("%03d", MilliSeconds));

        handler.postDelayed(this, 0);
    }

};

Runnable 객체의 run 메소드를 통해 스탑워치의 시간을 측정합니다. 

저는 Runnable 객체 선언에 대한 코드를 스틱코드를 이용해 빠르고 편하게 불러왔습니다.

stickode.com/detail.html?no=1873 - 안드로이드 스레드

 

 

위의 영상과 같이 스탑워치가 동작하게 됩니다.