관리 메뉴

HAMA 블로그

안드로이드에서 서비스 와 쓰레드의 차이 본문

안드로이드

안드로이드에서 서비스 와 쓰레드의 차이

[하마] 이승현 (wowlsh93@gmail.com) 2015. 6. 30. 11:59

http://roundhere.tistory.com/73 펌 


안드로이드 서비스(Services)


안드로이드 서비스는 U.I 없이 백그라운드에서 실행되는 기능을 말합니다.

예를들어 네트워크 통신,음악재생,I/O 작업등의 작업등이 해당된다.


* 서비스 타입

Started 타입

이 서비스는 startService() 호출하면 시작됩니다.

한번 시작되면 백그라운드에서 무기한으로 실행됩니다. 보통은 작업이 완료되면 스스로 종료됩니다.

예를들어 파일 다운로드, 음악재생 등이 있습니다.

Bound 타입

bindService() 호출후에 시작됩니다. 클라이언트와 서버 와 같이 동작합니다.

액티비티는 서비스에게 어떤 요청을 하고 서비스는 결과값을 반환합니다.

Bound 서비스는 여러 액티비티와 연결될 수 있습니다.


* 주의할점

서비스는 메인 스레드에서 실행됩니다. (서비스는 쓰레드가 아님, 별도의 프로세스도 아님)  

서비스가 CPU 자원을 많이 소모하는 작업이라면 서비스안에 스레드를 생성해서 작업하는게 좋습니다.

앱이 실행중일때만 필요한 기능이라면 스레드를 사용하는게 맞고 

앱이 실행중이지 않을때 실행되어야 한다면 서비스를 이용해야 한다.




안드로이드 어플은 액티비티, 서비스, 리시버들이 서로 엮이며 돌아가게 설계되는 경우가 보통이다.  액티비티는 보통 하나의 화면에 대응되어 사용자가 어플과 인터액션하고 서비스나 리시버 같은 다른 컴포넌트를 시작/중지시키는 그런 일을 한다.  "서비스는 UI에서 인터액션을 하면서 동시에 백그라운드로 음악듣기와 같은 것을 구현할 때 유용한 메커니즘이다" 라고 한다.  이 말은 보통의 스레드 활용을 연상시킨다.  그러면 안드로이드 서비스는 스레드와 어떤 관계인가?   


안드로이드에서 View를 포함하는 UI 오브젝트들은 자신을 콘트롤하는 스레드가 하나이어야 하기 때문에 안드로이드는 UI 오브젝트들이 UI 스레드에서만 돌게 만들었다.  그래서 UI스레드가 아닌 스레드들이 UI 오브젝트를 콘트롤하려면 Handler, Activity.runOnUIThread(Runnable), View.post(Runnable)나 AsyncTask를 써야 한다 (참고-1, 참고-2).  이런 스레드 활용 방법은 JAVA와 같은 개념이기에 심플하다.  


안드로이드 서비스에서 액티비티의 UI 오브젝트에 접근하려면 통상 그 서비스에서 intent를 날리고, 액티비티내에는 BroadcasterReceiver 인스턴스 객체를 임베드하고 onReceive() implementation에서 UI 오브젝트를 접근하는 형태를 이용한다.  이 구조는 스레드 만들면서 Runnable job을 던져주고, 적당한 때 스레드 스타트 하는 것보다 더 비동기적이다.  


서비스는 별도의 스레드인가?  아니다.  여기 첫머리에 분명 "서비스는 스레드가 아니다" 라 한다.  그럼 서비스는 무엇이냐?  존재 이유는?  위에서 말하기를, 


- 어플리케이션이 시스템에게 "여기 백그라운드에서 수행해야 할 일이 있거든" 알려주기 위해서란다.  그래서 manifest에 나타낸다.  그런데 서비스가 단순 백그라운드 작업 처리용도라면 통상적인 별도 스레드 만들어서 녀석에게 필요한 백그라운드 일을 던져 주면 되잖아.  뭐가 다르지?  아, 안드로이드 서비스는 별도의 라이프사이클이 있지.  Context.startService로 시작한 서비스는 액티비티가 죽던 살던 어찌 되던지 한번 돌기 시작하면 stopSelf()나 Context.stopService로 중지시키기 전까지는 여간해서는 계속 돈다.  반면 Context.bindService로 구동/바인딩 된 서비스는 바인딩된 서비스 클라이언트가 더 이상 존재하지 않으면 시스템이 서비스를 없앨수 있다 한다.  서비스도 언제든 죽을 수 있다 하지만, 일단 돌기 시작한 서비스는 stopService() 같은 것으로 명확히 중지시키기 전까지는 (상대적으로) 계속 돈다고 생각할 수 있나?  


서비스가 부모 어플리케이션이나 프로세스 상태와 무관하게 유지되는 백그라운드 작업처리 장치임에 비해 안드로이드 스레드는 자바 경우와 같이 부모 프로세스가 살아있는 동안에 runnable, running과 blocked 상태를 뱅글뱅글 거쳐 일을 마치면 dead 상태에 들어가는 단순한 흐름을 갖고 있다.  


- A facility for an application to expose some of its functionality to other applications.  (서비스를 갖고 있는) 어플리케이션이 다른 어플리케이션에게 자신의 기능을 공표할 수 있는 기능.  아니 이게 무슨 말인감?  클래스들의 모든 public 메소드가 다른 클래스에게 "나 이런 것 할 수 있으니 필요하면 불러 써" 하는 것 아닌감?  다시 잘 보자...  음, 어플리케이션간에 알려주는 관계라...  AIDL 서비스 얘기같다.


이곳에서 안드로이드가 멀티태스킹 지원을 어떻게 하려고 하는 지 읽어보니 안드로이드의 서비스, 스레드, 백그라운드 작업, 프로세스, 어플리케이션간의 관계에 대해 좀 더 이해가 깊어진다.  음. 안드로이드에서 일단 실행된 어플리케이션은 사용자가 죽이더라도 완전히 퇴출시키지 않도록 하고, 그러면서 (어플리케이션 바꾸기) 할 때 스왑공간이 부족하니 어플리케이션이 사용하는 메모리를 타이트하게 관리하도록 했다고.  이처럼 상충되는 요구조건은 사용자에게 보다 seamless한 UX를 제공하기 위해서란다.   


복잡하게 생각하지 말고 대충 생각해야 겠다.  


1. UI 스레드에서 시간이 요하는 태스크 처리가 필요하고, 계속 현재 UI 스레드가 foreground에서 놀고 있을 가능성이 많으면 간단히 별도 스레드를 만들거나 AsyncTask로 처리한다.  


2. 만약 부모 스레드가 더 이상 foreground가 아닐때에나, 그 스레드를 소유한 어플이 중지되었거나 관계없이 백그라운드에서 서비스가 계속 살아있으면서 일을 해야 하면 서비스로 구현한다.  그리고는 서비스내에서 스레드를 만들어 서비스가 수행해야 하는 작업을 스레드가 담당하도록 한다.  작업량이 많거나 작거나 관계없이 별도 스레드에서 하도록 한다.  안전하게...   만약 어플리케이션의 UI 스레드가 돌고 있다고 생각되면 Handler 클래스를 이용해도 되고, 잘 모르겠으면 BroadcastReceiver 클래스를 이용하여 어플리케이션 UI를 관장하는 스레드에게 접근한다.  BroadcastReceiver 클래스는 돌고 있지 않던 프로세스도 깨울 수 있다.    



Comments