안드로이드 어플은 액티비티, 서비스, 리시버들이 서로 엮이며 돌아가게 설계되는 경우가 보통이다. 액티비티는 보통 하나의 화면에 대응되어 사용자가 어플과 인터액션하고 서비스나 리시버 같은 다른 컴포넌트를 시작/중지시키는 그런 일을 한다. "서비스는 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 클래스는 돌고 있지 않던 프로세스도 깨울 수 있다.
안드로이드에서 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 클래스는 돌고 있지 않던 프로세스도 깨울 수 있다.
'소프트웨어 이야기' 카테고리의 다른 글
소프트웨어 품질은? 객체지향은? 잘 알고 있는 것 같은.... (0) | 2011.08.23 |
---|---|
Reflect on .NET 그러니까, 우리나라 SW 기술자에게 어떻게 희망을 갖도록 하나?! (0) | 2011.04.15 |
삼성전자 갤럭시S 원가는? (0) | 2010.10.28 |
아이폰4의 원가는? (0) | 2010.10.26 |
구글 넥서스원 스마트폰 원가는? (0) | 2010.10.25 |