메뉴 건너뛰기

XEDITION

Open

https://blog.naver.com/ssarang8649/220948756167



이전 포스팅에서
안드로이드 타이머의 기초에 이어
이번에는 주기적으로 메서드를 실행하다가

중간에 잠깐 타이머를 중지한 후 다시 실행하는 기능이 필요해서 구현해보려합니다.

본 포스팅에서 확인하실 수 있는 정보는

안드로이드 타이머 중지 후 재시작 할 때 유의 사항

입니다.


이전 포스팅에서
안드로이드 타이머를 작동시키기 위해서는
1. 타이머 클래스 (Timer) 가 필요하고
2. 타이머가 하게될 일 즉 타이머 태스크 (TimerTask) 
이 두가지가 필요하다는 것을 알 수 있었습니다.
 


하나의 타이머로
2개의 일을 할 수 있게 스케쥴링 할 수도 있는데요.

이전 코드에서
Timer  객체인 timer를 선언했고
이 timer에 3초에 1번씩 counter1을 올리도록 구현했었는데
여기에 또 하나의 TimerTask 객체인 tt2와 counter2 를 선언해서
이번엔 1초마다 tt2 를 실행하도록 추가하겠습니다.
이때 tt2가 하는일(Task)는 counter2 를 2개씩 올리는 것입니다.

import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import java.util.Timer; import java.util.TimerTask; public class MainActivity extends Activity { static int counter1 = 0; static int counter2 = 0; // 2번 Task로 올릴 카운터 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final TimerTask tt = new TimerTask() { @Override public void run() { Log.e("1번태스크카운터:", String.valueOf(counter1)); counter1++; } }; ////////////// 하나의 Task를 추가로 생성 /////////// final TimerTask tt2 = new TimerTask() { @Override public void run() { Log.e("2번태스크카운터:", String.valueOf(counter2)); counter2++;counter2++; //2씩 증가하도록 세팅 } }; ///////////////////////////////////////////////////// Timer timer = new Timer(); timer.schedule(tt, 0, 3000); ////////// 1초에 1번 tt2 TimerTask 를 실행하도록 설정 timer.schedule(tt2, 0, 1000); ///////////////////////////////////////////////////// } }


하나의 timer객체의 2개의 스케쥴이 확인하실 수 있습니다.
실행해보면..
아래와 같이 3초에 1번 counter1 을 1씩 올리는 tt 타이머태스크와
1초에 1번 counter2를 2씩 올리는 tt2 타이머 태스크가
동시에 작동하는것이 보입니다.


그렇다면 이렇게 걸린 스케쥴을 중지하고 싶을땐 어떻게 하느냐
그것을 위해 TimerTask 클래스는
cancel() 메서드를 제공합니다.
 

딱 3개 메서드 밖에 없네요...

cancel() : 타이머 태스크를 취소(중지)합니다.
run() : 타이머 태스크에서 정의한 run 메서드를 실행합니다.
scheduledExecutionTime() : 해당 타이머 태스크가 마지막에 실행한 시간을 timestamp 로 리턴합니다.



TimerTask 를 중지하고 재시작을 테스트해보기 위해
버튼을 2개 추가해보겠습니다.
그리고 버튼 이벤트에서 Timer 를 활용할 수 있도록 final 로 선언합니다.

 

import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import java.util.Timer; import java.util.TimerTask; public class MainActivity extends Activity { static int counter1 = 0; static int counter2 = 0; // 2번 Task로 올릴 카운터 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final TimerTask tt = new TimerTask() { //final로 변경 @Override public void run() { Log.e("1번태스크카운터:", String.valueOf(counter1)); counter1++; } }; ////////////// 하나의 Task를 추가로 생성 /////////// final TimerTask tt2 = new TimerTask() { @Override public void run() { Log.e("2번태스크카운터:", String.valueOf(counter2)); counter2++;counter2++; } }; ///////////////////////////////////////////////////// final Timer timer = new Timer(); timer.schedule(tt, 0, 3000); ////////// 1초에 1번 tt2 TimerTask 를 실행하도록 설정 timer.schedule(tt2, 0, 1000); ///////////////////////////////////////////////////// // 1번 버튼 "Stop" Button stopButton = (Button) findViewById(R.id.button); stopButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // tt 태스크 먼저 중지 tt.cancel(); Log.e("마지막 실행 시간", String.valueOf(tt.scheduledExecutionTime())); //tt.run(); //Log.e("purge:", String.valueOf(timer.purge())); } }); // 2번 버튼 "Start" Button restartButton = (Button) findViewById(R.id.button2); restartButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { timer.schedule(tt, 0, 3000); } }); } }

STOP 버튼을 누르면 
tt (counter1을 1개씩 증가하는 Task) 를 cancel 한다음 마지막 실행시간을 출력하게 하고
START 버튼을 누르면 정지한 스케쥴을 다시 구동하는 것이 목표입니다.

Stop을 누르면

위와 같이 1개의 Task 가 중지되어서 
tt2 만 살아있는것을 볼 수 있습니다.
이제 Start 버튼을 누르면 마법처럼 다시 tt 가 살아나서 다시 3초에 1번씩 출력되야 하는는데요
Start를 누르면
 

java.lang.IllegalStateException: TimerTask is scheduled already
에러를 뱉으며 멋지게 뻗어버립니다. ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ


여기서 결론
한 번 Cancel 한 TImeTask 는 다시 스케쥴 할 수 없습니다. (재사용이 불가합니다.)

그렇다고 해서 Cancel 한 TimeTask 가 아예 사라진 것(Terminated)도 아닙니다. 
아래와 같이 cancel 한 tt의 run() 메서드를 실행하도록 한다음
조낸 Stop 버튼을 눌러보면

Button stopButton = (Button) findViewById(R.id.button); stopButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // tt 태스크 먼저 중지 tt.cancel(); Log.e("마지막 실행 시간", String.valueOf(tt.scheduledExecutionTime())); ////////////////////////// 실행이라도 해보자 ////////////////////////// tt.run(); //Log.e("purge:", String.valueOf(timer.purge())); } });

위처럼 1번 태스크는 아직 건재합니다.
그래서 Timer 쪽에서 스케쥴 했떤 TimeTask 의 기억을 지울 수 있을지 한번 찾아봅니다.
 

출처 : 안드로이드 개발자 사이트

오! purge()라는 메서드가 있네요
타이머의 task queue 에서 cancel된 Task들을 다 지워버린답니다.

그러면 지운다음에 한번 시도해 볼까요 (위 코드에서 이미 있었던 purge를 살려봅니다)
 

// 1번 버튼 "Stop" Button stopButton = (Button) findViewById(R.id.button); stopButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // tt 태스크 먼저 중지 tt.cancel(); Log.e("마지막 실행 시간", String.valueOf(tt.scheduledExecutionTime())); //tt.run(); ////////////// purge로 timer 안의 cancel 된 TimerTask 들을 지우기!! Log.e("purge:", String.valueOf(timer.purge())); } });

 

Stop 버튼을 2번 누르니 
tt가 cancel 되고 곧 바로 timer 객체의 purge 메서드가 실행되면서
cancel 된 tt를 taskQueue 에서 지웁니다.
1개가 지워졌다고 출력되고 한번 더 누르니 이미 지워져 0개 지웠다고 출력하네요.

자 이제!! Start버튼을 누르면 되겠지

스티커 이미지
스티커 이미지

다시 적나라하게 뻗어버립니다...ㅋㅋㅋㅋ
메시지는 동일하네요
java.lang.IllegalStateException: TimerTask is scheduled already
타이머 태스크가 이미 스케쥴 되었다는 에러 메시지입니다.



여기서 다시 결론 
한 번 Cancel 한 TImeTask 는 다시 스케쥴 할 수 없습니다. Timer.purge() 해도 안됩니다.
(무조건 재사용이 불가합니다.)


아니 그럼 purge를 왜 만든거지..
개발 사이트에서 설명을 보면 purge는 거의 쓰지 않을것이라고 예언합니다.
왜냐면 timer 하나에 여러개 TimerTask 가 스케쥴 되어있을 경우
이미 cancel 한 Task 를 Queue에서 꺼내 Queue 공간을 낭비하지 않도록 하는 역할만 하기 때문입니다......


그렇다면
TimerTask 가 살아 있으니 다른 Timer를 선언해서 사용하면 될까?

라는 생각으로

Timer timer2 = new Timer(); timer2.schedule(tt, 0, 3000);

해도 똑같습니다.


즉 TimerTask 를 재사용하기 위해서는 TimerTask 객체를 새로 생성해야합니다.

왜 이리 만들었는지는 java님이 알겁니다..
아무쪼록 재 사용이나 새로 만드는 거나 결국 메모리 사용량은 같을것이기 떄문이라고 생각하고 넘어갔습니다.
Background 에서 돌리는것도 해보려 했는데 그러고보니 왜 굳이 
돌맹이 하나 재사용하려고 길을 하나 더 파나 하는 생각이 드네요...

따라서 스케쥴을 중지했다가 다시 실행시키려면
new TimerTask 정의 부분을 메서드로 변경해서
메서드를 실행할 때 마다 동일한 TimerTask 객체를 새로 만드면 됩니다.
심플하게 설명하기 위해 tt2는 지우고 1개의 task로 예를 들면 아래코드와 같습니다.

import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import java.util.Timer; import java.util.TimerTask; public class MainActivity extends Activity { static TimerTask tt; //////tt가 여러번 재정의 되므로 final을 static으로 변경 static int counter1 = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tt = timerTaskMaker(); /////////// / Timer 생성 ////////////// final Timer timer = new Timer(); timer.schedule(tt, 0, 3000); ////////////////////////////////////// Button stopButton = (Button) findViewById(R.id.button); stopButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { tt.cancel(); Log.e("Stop클릭", "tt 태스크를 cancel합니다."); } }); Button restartButton = (Button) findViewById(R.id.button2); restartButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { /////////////// 동일한 timer 를 재생성 하는 timerTaskMaker()로 교체 tt = timerTaskMaker(); Log.e("START 클릭", "tt 태스크를 재생성 합니다."); //////////////////////////////////// timer.schedule(tt, 0, 3000); } }); } ///////////////////////////////// TimerTask를 재생성하는 메서드 //////////////////// public TimerTask timerTaskMaker(){ TimerTask tempTask = new TimerTask() { @Override public void run() { Log.e("1번태스크카운터:", String.valueOf(counter1)); counter1++; } }; return tempTask; } }



위와 같이 메서드를 정의해서 선언할 때마다 TimerTask 를 재생성해서 리턴하게 한 다음 사용하면


위와 같이 Stop 을 누르면 tt 가 cancel되었다가
Start 를 누르면 tt 객체가 초기화 되어 다시 timer 스케쥴에 걸림을 볼 수 있습니다.



내용이 어쩌다 보니 너무 길어졌는데
저와 같은 짓(?)을 하게될 어떤 분들이
삽질 시간을 줄이셨으면 합니다.

 

요약

TimerTask 는 어떻게든 재사용이 불가합니다. 재사용을 고민할 시간에 그냥 new 생성하세요 ㅎㅎ

 



도움 되신 분의 공감은 힘이 됩니다☆
궁금하신 점은 덧글 주시면 아는 한도에서 성심껏 답변드립니다^^


모두 화이팅 하세요~!!

 

 

 

 


 

 

 

번호 제목 글쓴이 날짜 조회 수
32 linux buffer/cache 비우기 proin 2022.01.04 5
31 Python3를 사용하여 openalpr 실행 proin 2020.10.20 5
30 [android 개발] UI Thread 외부에서 UI 관련 작업 호출 하기 proin 2020.10.18 3
» 안드로이드 자바 타이머 (Timer) 정지 후 재시작 하기, java.lang.IllegalStateException: TimerTask is scheduled already proin 2020.10.17 3
28 안드로이드 타이머 사용법 기초 - Android Timer 주기적으로 메서드 실행하기 proin 2020.10.17 2
27 WINDOWS 10 탐색기 새로고침 버그 proin 2020.10.16 4
26 bjpublic / minecraft-python 마인크래프트와 함께 즐겁게 파이썬 proin 2020.08.27 2
25 bjpublic / aws 당신이 지금 알아야 할 AWS proin 2020.08.27 2
24 bjpublic / MLpythonpiece 머신러닝을 위한 파이썬 한 조각 proin 2020.08.27 3
23 bjpublic / smartwork 나만의 스마트워크 환경 만들기 proin 2020.08.27 3
22 bjpublic / whitehacker 화이트 해커를 위한 웹 해킹의 기술 proin 2020.08.27 2
21 bjpublic / TMI-Deeplearning 친절한 실전 딥러닝 수업 proin 2020.08.27 2
20 [펌] 포토샵 비정품 경고 알림 해제하기 proin 2020.05.11 1
19 패킷트레이서 5.3.3 file proin 2019.03.20 4
18 라즈베리파이 3 B+ 라즈비안 외 지원안되는 OS 설치 방법 file proin 2019.03.15 2
17 SoftEtherVPN proin 2019.01.08 6
16 옵테인 메모리 달면 HDD가 SSD 처럼 빨라진다? 정말? - IT 동아 proin 2018.10.01 2
15 XE exe 업로드 시 -x 붙는 현상 수정 방법 proin 2018.08.20 51
14 Vim 단축키 정리 proin 2018.06.09 4
13 윈도우의 VMware에 macOS Sierra 설치하기 proin 2018.05.30 4
위로