본문 바로가기
개발/안드로이드

[안드로이드] TimerTask 클래스를 사용한 스톱워치

by darksilber 2011. 6. 21.
반응형
팁스소프트에서 제공하는 프로그래밍과 관련된 자료나 정보들을 무단으로 복제하거나 게재하는 행위는
상호간의 신뢰를 무너뜨리는 행위이며, 법적인 문제를 야기할 수 있으므로 각별한 주의를 당부드립니다.
* 팁스소프트 저작권 정책 보기 - http://www.tipssoft.com/bulletin/tb.php/FAQ/637
이 자료들은 팁스소프트에서 제공하는 [ 알짜배기 ] 프로그램을 이용하면 더 편리하게 볼수 있습니다.
* 알짜배기 프로그램 받기 - http://www.tipssoft.com/bulletin/tb.php/QnA/8406
이번 자료에서는 자바언어에서 제공하는 Timer 클래스와 TimerTask 클래스를 이용하여 스톱워치를
구현하는 것에 대해 소개하도록 하겠습니다.
1. 타이머 사용하기
타이머란 일정 간격마다 명시한 행위를 반복적으로 수행하는 것을 말합니다. 타이머 기능은 여러가지
방법으로 구현할 수 있는데 일반적으로 많이 사용하는 Timer 클래스와 TimerTask 클래스를 이용한
방법에 대하여 설명하도록 하겠습니다.
타이머의 기능은 지정한 시간마다 명시한 행위가 수행될 수 있도록 제어하는 Timer 클래스의 기능과
반복되어 수행될 행위가 무엇인지 정의하는 TimerTask 클래스의 기능으로 나눌 수 있습니다.
Timer 클래스는 객체로 할당될 때 하나의 쓰레드를 생성하여 수행해야할 행위를 수 초 후에 한 번
또는 반복적으로 실행시킵니다. 하나의 Timer 클래스는 여러개의 반복 행위가 설정될 수 있으며,
각 행위는 복잡하거나 긴 시간을 요구하는 작업을 수행하면 쓰레드를 점유하여 다음 수행될 행위에
영향을 줄 수 있기때문에 가능한 빠르게 수행되어야 합니다.
TimerTask 클래스는 행위를 정의하는 클래스로 Runnable 인터페이스를 추가하여 구현한 클래스이며
Runnable 인터페이스의 run() 메소드에 행위를 정의하여 사용합니다.
Timer 객체가 타이머 기능을 시작할 때에는 schedule 메소드를 사용하며 타이머를 중지할 때에는
cancel 메소드를 사용합니다. 이 때 현재 실행하고 있던 행위가 있다면 해당 작업은 모두 마친후에
중지되며 수행이 예약되었던 다른 행위들은 모두 예약 취소됩니다. 이렇게 취소된 행위가 존재할 때
purge 메소드를 호출하면 대기중인 취소된 행위들이 제거되는데 그 수가 많지 않으면 사용하지
않아도 됩니다.
2. 스톱워치의 주요 기능
이번 강좌에서 구현하는 스톱워치 예제는 Start, Stop, Reset (또는 Record) 버튼을 이용하여
프로그램의 수행을 조작하고, 텍스트뷰에 스톱워치가 시작된 후부터 경과한 시간을 출력하며
리스트뷰에는 Record 버튼을 눌러 기록한 시간을 추가하도록 하였습니다.
아래의 그림은 프로그램을 실행한 기본 화면입니다.
Start 버튼을 누르면 스톱워치가 시작되며 Reset 버튼의 문자열이 Record 로 바뀌고, 다시 Stop
버튼을 눌러 정지 상태가 되면 Record 버튼의 문자열이 Reset 으로 바뀝니다. 시작 상태일 때
Record 버튼을 누르면 아래의 그림처럼 버튼을 누른 시점의 시간이 기록됩니다.
3. 스톱워치의 구성
스톱워치를 기능을 정의하려면 TimerTask 클래스를 상속받은 사용자 정의 클래스를 사용해야
합니다. 이 사용자 정의 클래스를 기본 Activity 클래스 밖에 선언하면 리소스 ID 를 이용하여
텍스트뷰를 얻어오는 것이나 스톱워치의 시작 시간값과 경과 시간값을 두 클래스가 공유하기
번거로워진다는 문제가 있기때문에 Activity 클래스 내부에 정의하여 사용하도록 하겠습니다.
3.1 TimerTask 클래스 상속받아 정의하기
기본 Activity 클래스 내에 아래의 Runnable 인터페이스와 UpdateTimeTask 클래스를 정의합니다.
UpdateTimeTask 클래스 내의 run 메소드는 Timer 객체가 생성한 쓰레드가 수행하기때문에
해당 메소드 내에 UI 에 관련된 작업이 있다면 View 클래스의 post 메소드를 호출하여 해당 작업을
메인 메소드가 대신 작업하도록 넘겨줍니다.
Runnable m_display_run = new Runnable() {
public void run()
{
// 텍스트뷰는 시간을 출력한다.
m_time_view.setText(m_display_string);
}
};
// TimerTask 클래스를 상속받는 클래스를 정의한다.
class UpdateTimeTask extends TimerTask
{
public void run()
{
// 현재 시간을 밀리초 단위로 얻어온다.
m_current_time = System.currentTimeMillis();
// 현재 시간에서 시작 시간을 빼서 경과시간을 얻는다.
long millis = m_current_time - m_start_time;
// 밀리초에 1000을 나누어 초단위로 변경한다.
int seconds = (int) (millis / 1000);
// 초단위의 시간정보를 60으로 나누어 분단위로 변경한다.
int minutes = seconds / 60;
// 초단위의 시간정보를 60으로 나머지 연산하여 초 값을 얻는다.
seconds = seconds % 60;
// 밀리초 단위의 시간정보를 10으로 나눈 몫에 100으로 나머지 연산을 하여
// 100의 자리와 10의 자리만 출력될 수 있도록 한다.
millis = (millis / 10) % 100;
// 출력할 문자열을 구성한다.
m_display_string = String.format("%02d : %02d : %02d", minutes, seconds, millis);
// 해당 문자열을 출력하도록 메인 쓰레드에 전달한다.
m_time_view.post(m_display_run);
}
};
3.2 스톱워치 시작하기
스톱워치를 중지했다가 다시 시작하는 것을 고려하여 구성합니다. 시작 시점에서 경과 시간이
저장된 변수와 시작 시간이 저장된 변수는 스톱워치를 정지할 당시의 값을 가집니다. 그러므로
경과 시간에서 시작시간을 빼면 얼마간 스톱워치를 작동시켰는지 알 수 있으므로 현재 시작하는
시작 데이터에 빼주어서 그 만큼 먼저 시작한 것처럼 값을 설정합니다.
public void startStopWatch()
{
if(m_timer == null) {
// 현재 시간에서 이전에 중지했던 시간(경과시간 - 시작시간)을 뺀다.
// 5초에서 중지를 누른 후 다시 시작을 누르면 1초후에 6초가 될 수 있도록 연산한다.
m_start_time = System.currentTimeMillis() - (m_current_time - m_start_time);
// 타이머 객체를 생성한다.
m_timer = new Timer();
// 사용자정의 TimerTask 객체를 넘겨주고, 100 밀리초 후에 수행되며,
// 200 밀리마다 반복 수행되도록 설정한다.
m_timer.schedule(new UpdateTimeTask(), 100, 200);
// Reset 버튼의 문자열(캡션명)을 Record 로 변경한다.
Button ext_btn = (Button) findViewById(R.id.id_ext_btn);
ext_btn.setText("Record");
}
}
3.3 스톱워치 정지하기
스톱워치를 정지한 후 해당 타이머에 null 을 저장하여 Start 버튼을 눌렀을 때 바로 시작할 수
있도록 합니다.
public void stopStopWatch()
{
if(m_timer != null) {
// 해당 타이머가 수행할 모든 행위들을 정지시킵니다.
m_timer.cancel();
// 대기중이던 취소된 행위가 있는 경우 모두 제거한다.
m_timer.purge();
m_timer = null;

// Record 버튼의 문자열(캡션명)을 Reset 로 변경한다.
Button ext_btn = (Button) findViewById(R.id.id_ext_btn);
ext_btn.setText("Reset");
}
}
3.4 경과시간 기록하기
스톱워치를 동작시키면 나타나는 Record 버튼을 이용하여 원하는 시간을 기록합니다.
public void recordTime()
{
// 리스트박스에 존재하는 항목 수를 얻는다.
int count = m_adapter.getCount();
// 리스트 박스의 마지막줄에 현재 시간을 추가한다.
m_adapter.insert(m_time_view.getText().toString(), count);
// 방금 추가한 항목을 선택한다.
m_list_view.setSelection(count);
}
3.5 경과 시간 및 리스트뷰 초기화하기
텍스트뷰에 출력되는 경과시간과 리스트뷰에 추가된 항목을 초기화합니다. 또한 경과 시간 정보와
시작 시간 정보를 초기화하여 0초부터 시작할 수 있도록 합니다.
public void recordTime()
{
// 리스트박스에 존재하는 항목 수를 얻는다.
int count = m_adapter.getCount();
// 리스트 박스의 마지막줄에 현재 시간을 추가한다.
m_adapter.insert(m_time_view.getText().toString(), count);
// 방금 추가한 항목을 선택한다.
m_list_view.setSelection(count);
}

반응형

댓글