Thread(스레드)와 Handler(핸들러) 그리고 루퍼(Looper)

Posted by ITPangPang
2016. 5. 22. 03:58 안드로이드(android)/Background(백그라운드)


Thread(스레드)와 Handler(핸들러)

...그리고 루퍼(Looper)


카테고리를 어떻게 분류할지 고민하다가 

   그냥 간단하게 백그라운드라고 정했습니다.


   사실 스레드 부분은 블로그 개설하자마자 첫번째 글로

   쓰고 싶었고, 실제로도 제목도 다 쓰고 글도 1~2시간

   쓰다가 나중엔 결국 다 지워버리고 그냥 포기했었습니다.


   그 당시에는 스레드와 핸들러 용어의 뜻과 그냥 사용방법 같은

   글을 준비하고 있었는데, 글을 쓰면서 이 중요한 스레드 핸들러 

   부분을 이렇게 대충 써도 되나 생각을 했었습니다.


   뭐 지금 쓴다고 해도 얼마나 제대로 쓸지는 모르겠지만...

   어쨌든 언젠가는 한번 정리를 해야 될 필요가 있다고 생각했었는데 그게 오늘이 된 것 같습니다.


   이게 시작을 참 어떻게 할지 고민을 많이 했습니다. 프로세스와 스레드를 비교하면서 접근을 해야할지

   아니면 그냥 코드로만 짜면서 접근을 해야할지... 뭐 결론은 프로세스에 대한 정의까지 알아가면서 

   정리할 필요는 없다고 생각해서 제목에 나온대로 Thread(스레드), Handler(핸들러), 루퍼(Looper)

   이 정도 선에서 글을 써보려고 합니다. 


   뭐 이글에서는 안나오겠지만 추가로 runOnUIThread() 라든지, AsyncTask에 대한

   글들은 당연히 써야겠지요.. 이 부분이 실질적으로는 개발에 많이 사용하므로..



Thread(스레드)란?


일단 멋있게 글상자에

스레드란?이라고 적었지만

백과사전이나 위키백과 같이

정확하게 설명할 자신은 없습니다


그냥 제가

 아는선에서 설명해보자면


하나의 앱을 실행시키면

그 앱은 하나의 흐름에 따라 진행됩니다


뭐 그 흐름이 스레드입니다.

스레드가 실이라는 뜻을 가지고 있듯이

실 한가닥을 타고 진행된다고 생각하면

됩니다.


이 한가닥의 실을

앱에서는 메인스레드(또는 UI스레드)라고

부릅니다.

스레드 하나로 진행되면

싱글스레드라고도 하죠..



그리고 개발자가 앱의 구성이나 기능상

한가닥의 흐름으로 진행될 수 없다고

생각되는 경우 메인스레드에

매듭을 묶어서 실을 더 연결해서

하나의 흐름이 아닌 다수의 흐름으로

바꿔줄 수 있습니다.

이때 개발자가 새로이 만들어 주는

실들을

작업쓰레드(Worker Thread) 또는 서브스레드

라고 합니다

스레드가 2개이상 돌아가는 경우

멀티스레드라고도 하죠.



메인쓰레드(UIThread)란?


메인쓰레드는

앱을 실행하면서 자동으로

생성됩니다.


개발자 입장에서 본다면

개발자가 따로

메인쓰레드를 생성하는

코드를 적어주지 않아도

onCreate를 타면 알아서

만들어집니다.


간단하게 이클립스나

안드로이드 스튜디오를

설치하자 마자

바로 실행시킬 수 있는

Hello World 코드도

메인스레드가 생성되어있는거죠


메인쓰레드를 왜 UIThread라고 하지?


뭐 답은 간단합니다.

메인쓰레드에서만 

눈에 보이는 화면을

컨트롤 할 수 있습니다.


위에서 개발자는 앱의 흐름상

작업스레드를 만들 수 있다고

설명했는데


만약 메인스레드가 아닌

작업스레드에서

눈에 보이는 화면을

변경하려고 시도 한다면??


만약

개발자가 작업스레드를

하나 만들었는데

여기서 TextView에 있는

글자를 변경하려고 한다면


이런 경고를 받고

앱이 종료됩니다


왜 종료가 되는지 알아보면

이런식으로 작업스레드에서는

안된다고 친절하게 알려줍니다


나름대로 안드로이드에서의

규칙입니다


그런데 왜 이런 규칙을

만들었을까요?


만약 이런 규칙이 

없었다면 어떻게 될까요?


시작을 실로 비유해서

설명했으니 이번에도

실로 나타내보자면


작업스레드를 만들어서

동시에 흐름을 2개를 만들었는데


메인스레드 흐름에서 

Hello World가 적혀있는

TextView를 Hello로 변경하라고

지시했습니다.


근데 때마침

작업스레드 흐름에서도

같은 Hello World가 적혀있는

TextView를 Hi로 변경하라고

지시했습니다.


근데 위 그림과 같이 그 시점이

정확하게 일치한다면?

과연 TextView에는 어떤

글자를 찍어줘야 할까요?

뭐 이런 예측 불가능한 상황을

피하기 위해서 규칙을 정해줬습니다.


(혹시나 해서 말을 덧붙이자면 

시점이 정확히 일치할 수는 없다고 알고있습니다

멀티스레드가 사용자가 느끼기에 동시작업이지

실제로는 사용자가 느낄수없을 정도로 빠른속도로

스위칭 한다고 알고있습니다.

A(B)-A(B) 동시 진행이 아니라

A-B-A-B를 아주아주아주아주아주아주아주

아주아주아주 빠르게 스위칭하면서 진행하는것으로

알고 있습니다)


작업스레드는 왜 만들어야 하나요?


그럼 규칙이고 뭐고

메인스레드에서 다 처리하면

되지 않을까요??


음..

우리가 생각하는

메인스레드의 속도가

아무리 빠르다고 생각해도


우리가 개발하면서

사용하는 코드는 메인스레드의

속도로 버틸수 없을만큼

엄청난 작업을 요구하는 코드입니다.


뭐 엄청난 작업의양을

정확한 수치로 표현할수는 없지만


대충 간단하게 코드를 

이렇게 짜봐도

btn.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
for(int i = 0; i<10000000;i++)
{
tv1.setText(""+i);
}
}
});

아마 버튼을 누르자마자

결과가 바로 뜨진 않을겁니다


몇초는 걸리겠죠..


이 정도 작업도 바로바로

안된다는 얘기입니다.


이 정도의 시간을 기다려주는

사용자는 많지 않습니다.

바로 종료버튼 누르겠죠


만약 여기서 더 작업량을

늘린다면?

btn.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
for(int i = 0; i<10000000;i++)
{
for(int j = 0; j<1000;j++)
{
tv1.setText("" + i);
}
}
}
});


뭐 개발자가 생각하기에는

코드 몇줄인데 생각하겠지만

메인스레드 하나로 돌린다면

아래와 같은 결과를 얻을 수 있습니다


뭐 위와같은

이유들로


시간이 오래걸리는 작업들은

메인스레드가 아닌 작업스레드를

생성해서 만들게 됩니다.


위의 예들은

그냥 멈추고, 아에 메시지창이 떠서

개발자가 개발하면서 직관적으로 볼 수 있어서

아 스레드 하나 돌려야겠네~

라고 느낄 수 있습니다.

(오히려 고마운거죠..)


그런데 멈출정도가 아닌정도로

애매~~한 작업들이 몇개가 쌓이고 쌓여서

따로 스레드를 두지 않는다면

나중에는 앱이 밀리는 현상을

볼 수 있습니다.

이게 왜 이렇게 느리지?

그때가서 어딜 바꾸지 어딜바꾸지?

하면 오히려 더 골치아파집니다..



근데 핸들러(Handler)는 뭐야?


핸들러는 뭐 해석해보면

처리하다에 -er이 붙었으므로

처리를 해주는 놈이라고 할까요


무엇을 처리해줄까요?

위에서 잠깐 나왔던

실 그림을 가져오면

자 이렇게 작업스레드를

생성해서 동시에 진행되고 있는데

이대로 그냥 쭉가면?


작업스레드를 만드는데에는

이유가 있을겁니다

뭐 일단 생성하고 지시는 

내렸는데 

그림으로만 보면

두 실이 만나는 부분이 없습니다


아래처럼 메인스레드와

연결할수 있는 연결고리가

필요합니다

이 연결고리

즉, 스레드간의 통신을

위한 장치가 바로

핸들러(Handler)입니다


그럼 루퍼(Looper)는?


메인스레드가 빨라서

사용자가 보기에 

바로바로 동시에 사사삭~

처리하는 것 같아도


나름대로 스레드 

자신만의

규칙이 있습니다.


어떤 기능을 구현하기 위해서

스레드한테 A,B,C,D를 하라고 

지시했을때


바로 A,B,C,D해! 이게 아니라


1초인 시점에 A를 해~

1.00000000001초에 B를 해~

1.00000000002초에 C를 해~

1.00000000003초에 D를 해~


이런식으로 지시를 하게 됩니다.

이렇게 A,B,C,D 순서가 잡히면

메시지큐(Message Queue)에 차곡차곡

쌓이는데


이 메시지큐에서 차례대로

꺼내서 핸들러(Handler)한테

전달해주는 역할을 하는

장치가 루퍼입니다.



자 백그라운드 첫번째글인

스레드,핸들러,루퍼의

개념적인 내용은 여기까지만 하도록

하겠습니다


다음글은 코드를 통해

접근을 할 예정이기 때문에

지금보다는 좀 더

실험적이고 깊이 파고드는

내용이 될 것 같습니다.



아직 저는 개발자가

된지 얼마 안 된 초보이기에

이런 어렵고 중요한 내용을

다루기에는 이론이 부족해서

틀린부분이나 적절하지 않은

예시가 들어갔을수도 있으니

참고하고 넘어가시면 좋겠습니다