마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

스레드가 이상하게 동작합니다.

0 추천
 Runnable timerLoop = new Runnable(){
        @Override
        public void run() {
            while(timerThreadEnable) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

                saveLog.writeLog("타이머"+timerSeconds, "" + Thread.currentThread().getName(),4,3);
                timerSeconds++;
                timerHandler.sendEmptyMessage(timerSeconds);
            }
            saveLog.writeLog("스레드종료", "" + Thread.currentThread().getName(),4,3);
        }
    };

    private Handler timerHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
                //saveLog.writeLog("타이머", "" + msg.what,4,3);
                tvKeepAliveTimer.setText("" + msg.what );
        }
    };

onCreate() 에서는

timerThread = new Thread(timerLoop);
timerThread.start();

 

onPause() 에서는

timerThreadEnable = false;

 

onResume 에서는

timerThreadEnable = true;

 

초기화 시킵니다

 

제가 의도한 동작은 액티비티에 무한루프 도는 스레드에서 매초 핸들러로 0부터 숫자를 전송해 

화면에 계속 출력하는것입니다. 브로드캐스트로 값을 받아서 0으로 초기화 시키는데 잘 작동하고

필요하지 않은것 같아서 생략했습니다

 

인터넷에 뒤져나오면 흔하디 흔한 코드로

플래그를 주어 액티비티가 꺼지면 종료되도록 해봤습니다.  인터럽트로 해보기도 했는데 같았습니다.

 

문제는 처음엔 잘 작동하다가 액티비티를 백그라운드로 돌리던지 destroy 하던 화면에서 없앤후 다시 실행하면 스레드는 분명 죽었다는 출력메시지를 뿜어냈었는데  두개의 스레드로 살아납니다

그래서 출력이

1    thread-9

2     thread-9

3     thread-9

4     thread-9

5     thread-9

(액티비티 종료)

(액티비티 다시켬)

1     thread-16

1     thread-17

2     thread-16

2     thread-17

3      thread-16

3      thread-17

4      thread-16

4      thread-17

이런식으로 원래 돌던 스레드는 죽고 갑자기 두개로 늘어나서 돌아갑니다.

pause될때 스레드객체나 러너블객체등을 null로 해봤지만 소용이 없었습니다.

create에서 스레드객체가 null이 일때만 새 스레드를 만들도록 해도 마찬가지였습니다

timerThread.setDaemon(true);  이옵션도 줘봤습니다

 

원래 이렇게 동작하는게 맞나요?

저걸 제가 의도한대로 포즈될때 종료되고 리줌될때 한개의 스레드만 작동되게 하려면 어떻게 해야할까요?

검색해보면 저런 코드는 널리고 널렸는데

다들 액티비티를 다시 켤때 상황을 어떻게 해결했는지 궁금하네요

초보에게 도움 부탁드립니다 ㅠㅠ

 

 

-------------------------------------------------------------------------------------------------

 

이걸 똑같이 타겟 sdk23 새 어플로

액티비티 하나에 저 스레드관련 클래스들만 모아서  테스트를 해봤는데

이건 또 제대로 동작하네요??;;

왜지;;

위에것은 프래그먼트 안에서 돌려서 그럴까요?

도대체 이해가;;;

 

qwertyshork (130 포인트) 님이 2020년 7월 10일 질문
qwertyshork님이 2020년 7월 10일 수정

1개의 답변

+1 추천

onPause시 timerThreadEnable 로 값 설정해도 Thread.sleep(1000); 때문에 바로 반영이 안되다 보니,

onPause=>onResume=>onPause=>onResume 같이 짦은 시간에 번갈아불리다 보면 꼬일 듯 합니다.

뭐 onPause 시 값 설정한 후 Thread join을 불러 Thread가 정리 될 때까지 기다리는것도 방법이긴 하지만, 

애시당초 Handler를 만드셨는데, 별도 Thread를 둘 필요 자체가 없는 듯 합니다.

 

sendMessageDelayed를 사용하면 일정 시간 이후 메세지를 수행할 수 있습니다.

아래 빨간색으로 표시한것 같이 입력해 주시면 1초 주기로 텍스트 뷰가 업데이트 되니,

private Handler timerHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {

        tvKeepAliveTimer.setText("" + msg.what );
        timerHandler.sendMessageDelayed(handler.obtainMessage(0, "" + (timerSeconds++)), 1000);
    }
};

onResume 시 

timerHandler.removeMessages(0) ; // 기존  메세지 요청 삭제 

timerHandler.sendMessageDelayed(handler.obtainMessage(0, "" + (timerSeconds++)), 1000); 를 호출 하고,

 

onPause 시 

timerHandler.removeMessages(0) ; 를 호출하게 변경하세요.

 

익명사용자 님이 2020년 7월 10일 답변
2020년 7월 10일 수정
아 이런방법이 있었네요;
답변 정말 감사합니다 ㅎㅎ
 
주기적 실행을 해야해서 당연히 스레드를 사용해야하는줄 알았어요.
질문의 코드대로 따로 액티비티를 만들어서 할 때는 왜 의도한대로 정확히 동작하는지에 대한 의문은 아직 남아있지만
일단 문제 해결은 됐네요 정말감사합니다 ㅎㅎ
어라...
잘동작 하는것 같았는데
로그를 찍어보니 똑같습니다.. ㅠㅠ 출력문이 계속 복사돼요;
신기하게도 저부분을 새프로젝트로 따로 빼서 타이머 부분만 출력을 해보면
의도한대로 정확하게 움직입니다...

정말 프래그먼트에서 쓸때는 뭔가 다른 처리를 해줘야하는걸까요?
의심되는 부분이 있으시면 아낌없이 말씀 부탁드립니다 ㅠㅠ
액티비티를 껏다 켯다 할때마다 계속 스레드가 복제가되고
sendMessageDelayed를 이용해도 마찬가지네요 이것도 아마 내부적으로 스레드 상에서 이뤄지는거라 그런거 아닐까요?
한개의 스레드만 의도한대로 액티비티 생명주기에 따라 동작하구요
나머지 복제된 스레드들은 액티비티가 꺼져도 계속 로그가 찍힙니다.
헐 자답니다...
테스트 한다고 포즈할때 timerHandler.removeMessages(0) ; 이걸 주석처리 해놨었네요....;;
죄송합니다;;;;
...