'Android Srvices'에 해당되는 글 1건

  1. 2013.10.04 Android Services
Programming/Android2013. 10. 4. 01:44

서비스(Services)

참조: http://developer.android.com/guide/components/services.html


서비스는 백그라운드에서 롱런 작동을 하는 컴포넌트이며 사용자에게는 보이지 않는다. 다른 앱 컴포넌트에서 이를 실행시킬 수 있고 사용자가 앱을 스위치 시킨다하더라도 동작한다. 게다가 컴포넌트는 서비스와 묶일 수 있고 프로세스통신이 가능하다(IPC). 예를들어 서비스는 네트워크 트렌젝션, 음악 실행, 파일 I/O 동작이나 컴텐트 프로바이더와의 상호작용을 백그라운드에서 핸들링 할 수 있다.


서비스는 기본저긍로 두가지 폼을 가진다.

1. Started

앱 컴포넌트가 startService() 메소드 호출을 통해 서비스를 시작할 수 있는데 이를 "started"라 한다. 서비스가 한번 시작되면 이를 시작한 컴포넌트가 소멸되더라도 이 서비스는 독립적으로 백그라운드에서 실행되게 된다. 보통은 시작된 서비스는 하나의 동작을 하고 이에대한 결과를 호출자에게 리턴하지 않는다. 예를들어 네트워크를 통해 파일을 다운받거나 업로드하는 작업이다. 이런 작업이 끝난후 서비스는 자동 소멸된다.

2. Bound

앱 컴포넌트가 bindService() 메소드 호출을 통해 서비스를 시작할 수 있는데 이를 "bound"라 한다. 바운드 서비스는 클라이언트-서버 인터페이스를 제공한다. 이 인터페이스는 서비스와 상호작용하거나, 질의를 던지고, 결과를 받고, 심지어 프로세스통신(IPC)를 가로지를 절차를 수행할 수 있다. 바운드 서비스는 다른 앱 컴포넌트와 바인드 되어있을 때만 동작한다. 다수의 컴포넌트가 이 서비스를 한번에 바인드 시킬 수 있지만 모든 바인드가 풀렸을때, 이 서비스는 소멸된다.


이는 서비스를 독립적으로 시행시킬지 컴포넌트에 바인드 시킬지의 문제인데 이것은 쉽게 다음 두개의 콜백 메서드를 구현하는 것의 문제이다. onStartCommand() 메소드는 컴포넌트가 이 서비스를 시작하는 것을 허가하는 것이고 onBind()는 바인딩을 허락하는 것이다.


앱이 시작되었는지 바인딩되었는지 아니면 둘다 인지 상관없이 다른 앱 컨포넌트는 이 서비스를 사용할 수 있다. 이는 액티비티가 intent에 의해 다른 앱에서 실행될 수 있는 것과 마찬가지 인다. 하지만 메니페이스 파일에 명시함으로써 서비스 개인화가 가능하다. 이는 밑에 메니페스트에서의 서비스 명시(Declaring the service in the manifest)에서 다시 이야기하자.


주의. 서비스를 실행할 때 Application Not Responding 에러를 방지하기위해 새로운 스레드를 구성하여 서비스를 지원하자.


기초(The Basics)

서비스 구현을 위해서는 서비스 클래스의 서브클래스를 생성해야 한다. 몇몇의 콜백 메소드를 오버라이딩해야한다. 다음과 같은

onStartCommand(): startCommand()로 호출된다. 한번 실행되면 독립적으로 백그라운드에서 동작하고 자신이 stopSelf()하거나 다른 컨포넌트가 stopService() 메소드를 호출해 주어야 멈춘다.

onBind(): bindService()에 의해 실행되며 서버-클라이언트 인터페이스를 제공해야하며 IBinder 클래스로 리턴한다. 이 메소드는 꼭 구현되어야하고 바인딩을 원하지 않으면 null로 리턴한다.

onCreate(): 서비스가 실행될때 최초 한번 실행한다(onStartCommand()나 onBind()전에). 서비스가 이미 시작된 시점에서는 호출되지 않는다.

onDestroy(): 서비스가 더이상 상용되지 않을때 호출되며 이때 스레드나, 등록된 리스너, 리씨버 등의 리소스를 클린 업 해주어야 한다.


만약 컴포넌트가 startService()로 서비스를 콜하면 (onStartCommand() 콜백 메소드 실행) 자신이 stropSelf() 메소드를 호출하거나 다른 컴포넌트에서 stopService()메소드를 호출할때까지 동작한다. 


이번에는 컴포넌트가 bindService()로 서비스를 콜하면 (onStartCommand() 콜백 메소드 실행하지 않음) 이를 콜한 컴포넌트와 바인딩 되어있을 때까지 동작하고 모든 클라이언트로부터 바인딩이 풀리면 시스템이 이 서비스를 소멸한다.


메니페스트에서의 서비스 명시(Declaring the service in the manifest)

액티비티와 같이 모든 서비스는 메니페스트 파일에 명시되어야 한다. <application> 안에 <service> 태그 생성하고 꼭 생성해야하는 어트리뷰트는 android:name이고 액티비티와 같이 이 이름은 한번 생성되면 변경될 수 없다.

<service> 엘리먼트의 더 많은 정보는 다음을 참조: http://developer.android.com/guide/topics/manifest/service-element.html


액티비티와 마찬가지로 인텐트 필터로 암시적 인텐트를 통해 서비스를 실행시킬 수 있다. 그리고 인텐트 필터를 설정하지 않으면 다른 앱에서 암시적으로 접근할 수 없고 명시적 그러니까 클래스 명을 기입하여야만 이 서비스에 접근할 수 있다. 게다가 서비스를 개인화 하길 원한다면 android:exported 에트리뷰트 값을 false로 해주면 인텐트 필터가 있더라도 이에 접근할 수 없다.


스타티드 서비스의 생성(Creating a Started Service)

위에서 설명한 것을 다시 설명하지 않겠다. 그저 startService()메소가 호출되면 onStartCommand() 콜백 메소드가 실행되고 Intnet 객체를 받아 정보를 얻는다. 그리고 서비스 과부화로 사용자와 인터렉트하는 액티비티가 문제가 있을 수 있으니 서비스는 따로 스레드 돌려라.


전통적으로 스타티드 서비스를 생성하기 위해 두가지 클래스를 익스텐드 한다.


1. Servie

이것이 모든 서비스들의 기본 클래스이다. 기본적으로 메인 스레드를 이용하기 때문에 서비스 동작을 위해 새로운 스레드를 생성하라. 이는 어떠한 액티비티의 동작도 느리게 할 수 있기 때문이다.

2. IntentService

이는 Service 클래스의 서브 클래스이며 한번 하나씩 모든 요청들을 핸들링 하기위해 워크 스레드를 이용한다. 모든 요청을 한번에 동작시킬 필요가 없을 때 최고의 방안이다. 단지 onHandleIntent() 메소드를 구현하고 각각의 질의에따라 intent를 받고 이를 백그라운드에서 실행시킨다.


IntentService 클래스의 익스텐딩(Extending the IntentService Class)

대부분의 스타티드 서비스가 동시에 모든일을 수행하지 않기 때문에 IntentService 클래스가 최고의 선택이 될 수 있다.


intentService 크랠스는 다음의 동작을 한다.

- 액의 메인 스레드와 별개로 onStartCommand()에서 받은 인텐트들을 실행할 디폴트 워크 스레드를 생성한다.

- onHandleIntent() 구현 메소드가 한번에 한 인텐트씩 워크 큐를 사용하여 동작한다. 그래서 멀티 스레딩에 대한 염려를 할 필요가 없다.

- 모든 요청이 다루어지면 자동으로 서비스가 종료된다. 그래서 stopSelf()를 해 줄 필요가 없다.

- onBind()의 경우 자도응로 null을 리턴한다.

- onStartCommand()의 경우 Intent객체를 받아 워크 큐에 쌓아 놓았다 순서대로 onHandleIntent() 메소드를 사용한다.


IntentService를 익스텐드할 때 생성자에 super(String) 를 명시해야하고 인자값 String 생설될 스레드의 이름이 된다. 그리고 onCreate(), onStartCommand(), onDestroy() 메소드를 오버라이딩 할 수 있지만 첫줄에 super 클래스의 메소드를 호출하는 것을 잊지 말아라 이는 서비스의 스레드의 라이프를 핸들링 한다. 하지만 onBind()의 경우 예외이다 즉, super 크래스의 메소드 호출이 필요 없다.


다음으로 동시 질의 처리가 가능한 서비스 클래스의 익스텐드를 보겠다.


서비스 클래스의 익스텐딩(Extending the Service class)

만약 워크 큐를 통한 스타트 요구를 관리하느 데신 밀티스레딩을 이용한 서비스의 요구 처리가 필요하면 Service 클래스를 익스텐딩하여 구현할 수 있다.


구현은 스레드를 생성에 따라 달라질 수 있으며 onStartCommand() 메소드에서 어떤 int 값을 리턴하느냐에 따라 시스템이 이 서비스를 처우가 달라진다(소멸 여부). 다음은 리턴 벨류에 대한 설명이다.


START_NOT_STICKY

만약 시스템이 onStartCommand()를 리턴하고 서비스를 소멸시킨다면, 미결의 인텐트가 존재하지 않는한 서비스를 다시 생성하지 않는다. 이것은 필요하지 않을 때나 앱이 어떠한 완료되지 일을 쉽개 재시작할 수 있을 때 서비스를 돌아가는 것을 막는 가장 안전한 방법이다.

START_STICKY

만약 시스템이 onStartCommand()를 리턴하고 서비스를 소멸시킨다면, 서비스를 새로 생성하고 onStartCommand()를 호출하지만 마지막 인텐트는 전달하지는 않는다. 대신에 서비스를 시작시키기 위한 미결의 인텐트가 있는 것을 제외하고 시스템는 onStartCommand()를 null 인텐트를 인자로 호출한다. 이경우는 이 인텐트들은 전달된다. 이것은 명령을 실행하지않지만 독립적으로 실행되고 일을 기다리는 미디어 플레이어나 그와 관련된 서비스들에 적당하다.

START_REDELIVER_INTNET

만약 시스템이 onStartCommand()를 리턴하고 서비스를 소멸시킨다면, 서비스를 새로 생성하고 onStartCommand()를 호출하며 서비스에 전달된 마지막 인텐트는 전달한다. 모든 미결의 인텐드는 차례 차례 전달된다. 이것은 즉각적으로 재점유되는 파일 다운로드 같은 활동적으로 활동하는 일을 위한 서비스에 적합하다.


서비스의 시작(Starting a Service)

 인텐트를 인자로 startService() 메소드를 사용하여 서비스를 동작시킬수 있다. 그러면 onStartCommand() 콜백 메소드가 호출되고 만약 서비스가 처음 동작하는 것이라면 onCreate() 콜백 메소드가 먼저 실행되고 onStartComand() 메소드가 실행된다.


만약 서비스의 결과를 받아보고 싶다면, 서비스를 동작시킨 클라이언트가 브로드케스트를 위해 getBroadcast()로 PendingIntent를 만들어 Intent에 실어 서비스에 보낸다. 서비스는 이 브로드케스트를 이용하여 결과를 전달할 수 있다.


서비스 중지(Stopping a service)

 서비스는 각가의 라이프 사이클을 관리해야한다. 그렇지 않으면 시스템이 메모리를 회수하지 않는 한 서비스는 소멸되거나 멈추지 않고 onStartCommand()를 리턴한 후 계속 실행될 것이다. 그래서 stopSelf()나 stopService()메소드로 이를 정지시켜야 한다.


하지만 다수의 시작 요청에서 문제가 있을 수 있기 때문에 stopSelf(int)를 이요하여 시작요청에서 onStartCommand()의해 전달 받은 startId를 통해 각각의 서비스를 소멸시킬 수 있다.


바운드 서비스의 생성(Creating a Bound Service)

bindService() 메소드를 통해 서비스가 호출되며 서비스에는 onBind() 콜백 메소드가 구현되어 있어야하면 이는 IBinder 객체를 리턴한다. IBinder 객체는 서비스와 커뮤니키이션 하기위한 인터페이스를 가지고 있다. 이 서비스는 바인드된 앱들을 위해 존재하기 때문에 더이상 바인드된 앱이나 컴포넌트가 없다면 서비스는 소멸된다. (그래서 바운드 서비스를 정지 시킬 필요는 따로 없다.)


바운드 서비스를 생성하기 위해 클라이언트가 어떻게 서비스와 커뮤니테이션할지 인터페이스를 정의 해야한다. 서비스와 클라이언트간의 인터페이스는 IBinder 객체에 있어야하며 이는 onBind() 콜백 메서드의 리턴 값이다. 클라이언트가 IBinder 객체를 받으면 이것이 서비스와 인터페이스를 통해 통신하다.


다수의 클라이언트가 한번에 서비스와 바인드 될수 있다. 클라이언트가 서비스와의 통신이 끝나면 클라이언트는 unbindService() 메소드를 호출 할 수 있다. 그리고 모든 클라이언트가 바인드를 끝내면 서비스는 소멸 된다.


바이드 서비스의 구현은 다양한 방법이 있고 스타티드 서비스보다 더욱 복잡하다. 그래서 이 부분은 파트를 나누어 토의해 보자 참조:http://developer.android.com/guide/components/bound-services.html


사용자에게 공지 전달(Sending Notifications to the User)

서비스는 Toast Notifications나 Status Bar Notifications 를 통해 이벤트의 사용자에게 통지할 수 있다.

Toast Notification: http://developer.android.com/guide/topics/ui/notifiers/toasts.html

Status Bar Notifications: http://developer.android.com/guide/topics/ui/notifiers/notifications.html


Toast Notification은 잠시 화며에 메세지를 뛰웠다 사라지며 Status Bar Notifications의 경우 상태 바에 메시지가 노출되고 사용자가 이를 선택하여 액티베이트를 실행하는 등의 실행을 할 수 있다.


화면 전면에서 서비스 동작(Running a Service in the Foreground)

화면 전면의 서비스는 사용자가 이 서비스를 정확하게 인지하고 있다. 그래서 시스템이 메모리가 없을때 이 서비스를 죽일 수 없다. 전면의 서비스는 상태바에 이 서비스 상태를 공지해야 한다.


예를 들어 서비스로부터 음악을 실행시키는 음악 플레이어는 화면 전면에서 설정되어야한다 왜냐하면 사용자가  이 동작에 대해 정확하게 알고 있기 때문이다. 상태바는 현제 나오는 노래를 나태낼 수 있고 이를 통해 액티비티를 실행시키고 음악 플레이어와 상호작용할 수 있다.


이 서비스를 실행하기위해 startForeground() 메소드를 사용하며 이 메소드는 두가지 파라미터가 있다. 하나는 공지를 구분할수 있는 유일한 인티져 값과 Notification 객체이다. (요기서 인티져 값은 0 일수는 없다.)


이서비스는 stopForeground() 메소드로 삭제할 수 있으며 이는 boolean 값을 리턴한다. 이는 상태바 공지의 삭제위무를 같이 알려준다.


서비스의 라이프 사이클 관리(Managing the Lifecycle of a Service)

서비스의 라이프 사이클은 액티비티의 라이프 사이클보다 간단하지만 사용자가 인식하지 못하게 백그라운드에서 동작하기 때문에 서비스의 생사에 좀더 세심한 관심이 필요하다.


두가지 서비스 라이프 사이클이 있다.

- 스타티드 서비스(A started service)

startService()에 의해 실행된다. 독립적으로 동작하면 stopSelf() 메소드에 의해 멈춰진다. stopService()를 통해 다른 컴포넌트에서 정지시킬 수 있다. 서비스가 중지되면 시스템은 이를 소멸시킨다.

- 바운드 서비스(A bound service)

binService() 메소드가 다른 컨포넌트(클라이언트)에 의해 호출된다.클라이언트는 IBinder 객체를 통해 상호작용한다. 클라이언트느 unbindService() 메소드로 바인드를 풀수 있다. 다수의 클라이언트가 하나의 서비스에 바인드 될 수 있고 모든 클라이언트가 이 관계를 끊으면 시스템은 서비스를 소멸시킨다. (서비스가 자신을 정지시킬 필요가 없다.)


이 두가지 서비스 라이프 사이클리 완전히 분리되어있지는 않다. 예를들어 startService()로 시작된 음악 플레이어에 bindService() 메소드로 바인딩 시킬 수 있다. 이러한경우 stopService()나 stopSelf() 메소드는 서비스를 멈출 수 없으며 모든 클라이언트를 언바인딩 시킬때 서비스가 정지 된다.


라이프 사이클 콜백 구현(Implementing the lifecycle callbacks)

Service() 객체를 익스텐드한 클래스는 onCreate(), onStartCommand(Intent intent, int flags, int startId), onBind(Intent intent), onUnbind(Intent intent), onRebind(Intent intent), onDestroy() 메소드를 오바라이딩 함으로써 서비스 라이프 사이클을 관리 할 수 있다.



더 많은 Bound Services 의 정보는 다음 링크에서 참조: http://developer.android.com/guide/components/bound-services.html



Posted by Brian B. Lee