본문 바로가기
프로그래밍/Android

안드로이드 쓰레드(1)

by Daniel.kwak 2018. 11. 12.

목표

1.안드로이드 쓰레드에 대해 알아본다.(정의, 메인쓰레드가 동작하는 방식, 필요한 이유, ANR)

2.핸들러, 루프, 메세지 큐 등에 대해 알아본다.

3.Message와 Runnable에 대해 알아본다.

4.HandlerThread 클래스에 대해 알아본다.

5.AsyncTask에 대해 간략히 알아본다. 

5.쓰레드 구현 방법에 대해서 알아본다.(Thread 클래스 상속, Runnable 인터페이스 구현)




안드로이드 멀티쓰레딩

안드로이드와 같은 클라이언트 프로그래밍에서 가장 복잡하고도 중요한 부분은 여러 쓰레드에서 실행되는 코드를 작성해야 하는 경우이다.

공식 안드로이드 문서에서는 "기본적으로 같은 애플리케이션의 모든 컴포넌트는 같은 프로세스 및 쓰레드(메인 쓰레드 혹은 UI쓰레드)에서 실행된다." 라고 말한다. 다시 말해 또 다른 쓰레드를 생성하거나 새 쓰레드를 실행하는 함수를 암시적으로 호출하지 않으면 안드로이드 애플리케이션에서 수행하는 모든 기능은 메인 쓰레드에서 실행되게 된다. 즉 어떠한 동작이나 이벤트가 작업이 오래걸릴 경우, 새로운 쓰레드로 작업을 분산시켜주지 않는다면 Application Not Responding(ANR)이 발생하게 되고 이는 유저입장에서 매우 치명적이다. 




Looper , Message Queue , Handler

안드로이드의 메인 쓰레드는 애플리케이션 생명주기 동안 Looper 클래스를 통해 앱이 죽을때 까지 계속 살아있다.  Looper 클래스는 현재 쓰레드에서 Message Queue를 조회하는 루프를 생성한다. 메세지 큐에 대한 쿼리는 새로운 메세지가 오기 전까지는 대기 상태이며 쓰레드가 슬립할 수 있도록 한다.  

이 때 Message Queue의 element는 Message 혹은 Runnable 객체이다.



Handler는 Looper로부터 받은 메세지를 실행하거나 다른 쓰레드의 post( ) , sendMessage( ) 메소드를 통해 들어온 메세지를 Looper에 전달한다. 쓰레드의 통신장치라고도 할 수 있을것이다. 

또한 Handler는 자신을 만든 쓰레드에 종속되며, 당연히 Message Queue를 해당 쓰레드와 공유한다.

handleMessage( ) 메소드를 통해 외부나 자기의 쓰레드에 쌓인 Message Queue내용을 처리한다. 



메인 쓰레드의 모든 작업은 Handler 객체를 통한 직접 실행이든, 안드로이드 API(예를 들면 runOnUiThread()) 를 통한 간접 실행이든 해당하는 메세지 큐로 메세지를 보냄으로서 이뤄진다. 애플리케이션의 메인 쓰레드 Looper는 Contex.getMainLooper()를 통해 알 수 있다.


메인 쓰레드는 자동으로 Looper가 할당되어 있어 무한히 Loop를 돌면서 Message Queue의 객체를 처리하지만, 새로 생성한 쓰레드는 기본적으로 Looper가 할당되어 있지 않고 run( ) 메소드만 실행하고 종료한다. 따라서 새로 생성한 쓰레드에서 메세지를 전달받기 위해서는 prepare( ) 메소드로 루프를 생성하고, loop( ) 메소드를 통해 루프를 무한히 돌게 하여 메세지 객체를 Handler에 전달하게 한다. 생성된 loop는 quit와 quitSafely메소드를 통해 종료된다. 




Message , Runnable

Message는 쓰레드 간 통신을 담은 객체이자 Message Queue의 원소로써 일감의 단위로 Handler에 보낼 수 있다. 일반적으로 new Message와 같이 새로 생성하지 않고 안드로이드의 Message pool을 이용하여 Message를 만든다. 이때 목적 Handler와 what의 내용을 담아서 만들 수 있다. 또는 Handler로부터 메세지를 생성할 수도 있다.

Runnable은 쓰레드가 생성될 때 생성자로 Runnable의 인터페이스를 구현한 객체를 생성하여 run( ) 을 구현하는 경우에 사용한다.

따라서 Message가 쓰레드와 통신할 내용과 목적 Handler를 담고 있다면, Runnable은 실제 구현될 코드(run)를 담고 있다는 차이점이 있다. 




HandlerThread

안드로이드의 쓰레드는 자바의 쓰레드를 사용하므로, 기본 Looper와 Message Queue를 가지지 않는다는 단점이 있다. HandlerThread는 자바의 Thread를 안드로이드에 맞게 확장한것으로, Looper와 MessageQueue를 기본으로 가지고 있는 클래스이다. 





AsyncTask

안드로이드에서 하나의 클래스 안에서 UI작업과 백그라운드 작업을 구현할 수 있도록 제공하는 클래스이다. 캡슐화가 잘 되어 있어서 가독성이 쉽고, 쓰레드나 핸들러의 기본 원리를 몰라도 백그라운드 작업이 가능하다. 그러나 스케쥴링 할 수 있는 작업의 수가 제한이 되어 있고, 몇 초 정도의 짦은 작업에서만 이상적으로 작동한다는 단점이 있다. 그리고 AsyncTask객체를 한 번만 실행할 수 있으므로 매번 실행할 때마다 new로 클래스를 생성해줘야 한다.

따라서 Thread와 Handler를 사용하면 복잡성이 증가하지만 그 만큼 자유롭고 세밀한 개발이 가능하다.

'프로그래밍 > Android' 카테고리의 다른 글

안드로이드 방향 전환  (0) 2018.12.06
안드로이드 컴포넌트  (0) 2018.12.06
안드로이드 AlaramManager  (0) 2018.12.05
Android Material CalendarView  (1) 2018.12.05
안드로이드 Camera의 영상 출력하기  (0) 2018.12.05
Android SurfaceView  (0) 2018.12.04