서비스는 백그라운드에서 동작하는 작업을 수행한다. 따라서 서비스를 실행한 앱을 다른 앱으로 전환하더라도 서비스에서 시작한 작업은 백그라운드에서 계속 실행된다.
서비스는 크게 3가지 타입이 있다.
포그라운드 서비스 : 알림창에 서비스가 실행 중인 것을 표시해준다. 대신 시스템에 의해서 강제로 종료되지 않는다.
백그라운드 서비스 : 사용자에게 보이지 않는 백그라운드에서 작업을 수행한다. 시스템 리소스가 부족할 경우 강제 종료될 수도 있다.
바인드 서비스 : 서비스와 서비스를 호출하는 앱 구성 요소가 서버-클라이언트와 같은 형태로 상호작용한다. 따라서 여러 프로세스에서 같은 서비스에 바인딩하여 작업을 수행할 수 있다.
여기서는 가장 기본적인 서비스 형태인 백그라운드 서비스, 동작 방식이 조금 다른 바인드 서비스, 비동기 처리에 용이한 IntentService의 생명주기와 사용법을 살펴볼 것이다.
서비스는 다음과 같은 생명주기를 가진다.
서비스 생명주기
백그라운드 서비스
startService()를 통해 최초 서비스 실행 시 onCreate()가 호출된다. 그 후에는 onStartCommand()가 호출된다. 서비스를 종료하기 위해서는 stopService()를 실행하거나 서비스 자체에서 stopSelf()를 실행하면 된다. 그러면 onDestroy()가 호출되어 서비스가 종료된다.
주요 함수
startService() : 서비스를 실행한다.
onCreate() : 서비스가 최초 생성될 때 한 번 호출된다. 이미 실행 중인 서비스라면 이 함수는 호출되지 않는다.
onStartCommand() : 앱의 다른 구성 요소에서 서비스를 실행하면 이 함수가 호출된다. 이 함수가 호출되면 서비스가 시작된 것이며 백그라운드에서 작업을 수행한다.
onDestroy() : 서비스가 소멸될 때 호출된다.
stopSelf() : 서비스가 스스로 중단한다.
stopService() : 다른 구성 요소가 서비스를 중단한다.
바인드 서비스
bindService()를 통해 최초 바인드 할 때 onCreate()가 실행된다. 그 후에는 onBind()가 호출된다. 바인드를 해제하기 위해서는 unbindService()를 실행하면 된다. 그러면 onUnbind()가 호출되고 onDestroy()가 호출되어 서비스가 종료된다.
주요 함수
bindService() : 서비스에 바인딩할 때 사용한다.
unbindService() : 서비스를 언바인딩 할 때 사용한다.
onBind() : 다른 구성 요소가 서비스에 바인딩되면 호출된다.
onRebind() : (onUnbind() 함수의 리턴값이 true인 경우) unbind 된 후에 서비스 실행 중일 때 다시 bind시 호출된다.
onUnbind() : unbindService() 호출 시 호출된다.
(서비스를 호출한 구성 요소)
onServiceConnected() : 서비스에 바인드 되었을 때 호출된다.
onServiceDisconnected() : 서비스를 호스팅 하는 프로세스가 중단되거나 종료되어 예기치 않게 서비스에 연결이 끊어졌을 때 호출된다. 클라이언트가 언바인딩 할 때는 호출되지 않는다.
IntentService
기본 스레드와는 별개로 onStartCommand()에 전달된 모든 인텐트 실행을 위한 작업 스레드를 생성한다. 전달된 인텐트는 작업을 위한 큐에 순차적으로 쌓이고 루퍼에 의해서 차례로 onHandleIntent()에 전달된다. onHandleIntent()에서 작업이 완료되면 서비스를 종료한다. 따라서 별도의 멀티 스레딩 처리를 고민하지 않아도 된다.
다른 함수는 오버라이딩하지 않아도 되지만 onStartCommand()는 반드시 오버라이딩을 하고 super.onStartCommand()를 호출해야 한다. 일반 서비스에 비해서는 함수가 적어 훨씬 간결하다.
주요 함수
onStartCommand() : 인텐트를 작업 큐로 보낸 후 onHandleIntent()를 호출한다.
onHandleIntent() : 워커 스레드에 의해 순차적으로 호출되어 필요한 작업을 수행한다.
첫 번째 버튼은 startService()를 통해 일반적인 백그라운드 서비스인 MyService를 실행하여 음악을 재생한다.
두 번째 버튼은 stopService()를 통해 서비스를 종료하여 음악 재생이 멈춘다.
세 번째 버튼은 bindService()를 통해 바인드 서비스를 실행하여 음악을 재생한다.
네 번째 버튼은 unbindService()를 통해 서비스를 언바인드 한다.
다섯 번째 버튼은 startService()를 통해 IntentService인 MyIntentService를 실행하여 음악을 재생한다. 비동기로 동작이 되기 때문에 여러 번 실행 시 비동기로 음악이 연속 재생된다.
첫 번째 버튼으로 서비스 실행 중에 두 번째 버튼으로 바인드 서비스를 하고 세 번째 버튼으로 언바인드 한 후 바로 바인드를 하면 onRebind()가 호출된다. (1-3-4-3 순서) onUnbind()의 리턴값이 true이기 때문이다.
MyService.kt
MyService의 주요 함수는 위와 같다.
첫 번째 버튼은 일반적인 백그라운드 서비스로 onStartCommand()가 호출되어 핸들러를 통해 음악을 재생한다.
두 번째 버튼을 누르면 stopService()를 호출하여 서비스를 종료하여 음악 재생이 멈춘다.
세 번째 버튼을 눌렀을 때는 MyService에 바인딩된다. 이때는 onBind()가 호출되어 음악을 재생한다.
네 번째 버튼을 눌러서 언바인딩을 하면 onUnbind()가 호출된다.
MyIntentService.kt
다섯 번째 버튼을 누르면 MyIntentService를 호출한다. IntentService이기 때문에 오버라이딩 해야 하는 함수가 적어서 구성이 간단하다. 버튼을 연속적으로 누르면 onStartCommand()는 전달받은 인텐트를 작업 큐에 넣을 것이고 그 후 순차적으로 onHandleIntent()에 전달된다. 그러면 음악이 비동기적으로 여러 개 재생된다.