Concepts of Service
1. Service
- 백그라운드에서 오랜 시간동안 수행되는 업무를 처리하기 위한 컴포넌트
- 액티비티에서도 Thread나 Coroutine을 이용해 백그라운드에서 업무 수행이 가능
- 위의 것들은 화면 반응성이 있는 백그라운드 업무(수행 결과가 화면에 찍히는 등..)
- 서비스는 화면 반응성이 없거나 아주 드물게 발생하는 백그라운드 업무만 담당
- 또한 다른 애플리케이션이 작동 중이어도 우리 애플리케이션이 작동해야하는 것이 있는 경우 담당
- 화면 출력 능력은 가지지 않는 컴포넌트
2. Service 사용 방법
1) Service를 상속받아 작성
class MyService: Service() {
override fun onBind(intent: Intent): IBinder? {
return null
}
}
- 특정 기능이 추가된 Service의 서브 클래스를 상속받아 작성하기도 함
2) AndroidManifest.xml에 등록
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"></service>
- name 속성 생략 불가
- Service 또한 Intent로 실행되는데 명시적 인텐트로 실행시키려면 name만 써도 되지만 암시적 인텐트로 실행시키려면 intent filter 작성 필요
3) startService()에 의해 Service 실행
val intent = Intent(this, MyService::class.java)
startService(intent)
- 외부 앱의 서비스라면 setPackage() 함수를 이용해 실행하고자 하는 앱의 패키지명(식별자) 명시
4) stopService()에 의해 Service 종료
val intent = Intent(this, MyService::class.java)
stopService(intent)
- 화면 반응성이 없어 유저에 의해 종료될 수 없기 때문에 필요 없는 순간 코드에서 종료
Service Lifecycle
1. Activity Lifecycle vs Service Lifecycle
- 안드로이드 4대 컴포넌트 중 Activity와 Service는 Lifecycle 정리를 해주어야 함
- 서비스를 실행시키는 방법이 startService() 함수와 bindService() 함수 두개가 있음
- 어느 함수를 이용해 서비스가 실행되는지에 따라 서비스의 라이프 사이클이 다름
- 서비스 클래스는 싱글톤으로 동작
- 싱글톤 : 하나의 클래스가 동작할 때 단 하나의 객체로만 동작
- 액티비티 클래스에 인텐트를 발생 시켜 액티비티를 실행 → 액티비티 객체가 생성되어서 동작 → 똑같은 액티비티를 실행시키기 위한 인텐트가 한번 더 발생하면? → 액티비티는 싱글톤으로 동작하지 않기 때문에(액티비티는 화면 출력 목적이기 때문에) 또 하나의 객체가 발생
- 서비스 클래스에 인텐트를 발생 시켜 서비스를 실행 → 서비스 객체가 생성되어서 동작 → 똑같은 서비스를 실행시키기 위한 인텐트가 한번 더 발생하면? → 객체가 다시 생성되지 않고 이전에 생성된 객체를 그대로 이용(서비스는 화면 출력 목적이 아니기 때문에)
2. Service Lifecycle
1) startService()로 구동
- 객체 생성 → Oncreate() 호출 → onStartCommand() 호출 → 서비스 실행 → stopService()로 인텐트 발생 → onDestroy() 호출 → 서비스 종료
- 하나의 서비스가 실행되고 있는데 같은 서비스를 실행시키기 위한 인텐트가 발생해도 객체를 발생시키지 않음 → onCreate()는 서비스 객체 생성 때 한번만 호출, onStartCommand()만 다시 호출(매개변수에 호출시킨 인텐트가 들어감)
- 인텐트가 발생되어 요청이 들어올 때마다 onStartCommand()에서 쓰레드를 하나씩 만들어서 멀티쓰레드 환경으로 프로그램이 동작되는 등의 처리를 해주면 됨
2) bindService()로 구동
- 객체 생성 → Oncreate() 호출 → onBind() 호출 → 서비스 실행 → unbindService()로 인텐트 발생 → onUnbind() 호출 → onDestroy() 호출 → 서비스 종료
- 하나의 서비스가 실행되고 있는데 같은 서비스를 실행시키기 위한 인텐트가 발생해도 객체를 발생시키지 않음 → onCreate()는 서비스 객체 생성 때 한번만 호출, onBind()만 다시 호출, 종료시 onUnbind()도 요청 단위대로 호출
startService
1. startService
- 서비스 구동을 위해 인텐트를 발생시켜야 함, 인텐트를 발생시키는 함수가 startService()
- startService()에 의해 Service가 실행되면 특정 객체가 리턴되지 않는다
- 상호 데이터를 전달할 직접적인 방법이 없다, 즉 인텐트에 의해 발생된 후에 서비스를 구동시킨 곳(액티비티, 리시버, 다른 서비스 등)과 데이터를 서로 전달할 방법이 없다
- 데이터를 전달 받을 곳에 BroadcastReceiver를 정의하고 데이터 전달이 필요할 때 이 BroadcastReceiver를 실행시키면 Broadcast Intent에 Extra 데이터로 전달시키는 방법을 이용
2. 데이터 전달 예시
- 액티비티에서 유저 이벤트나 유저가 등록한 데이터를 서비스에 전달하는 경우
① Intent에 extra data로 데이터를 담는다
② Intent를 발생시켜서 Service 내부의 BroadcastReceiver가 실행되도록 한다
③ BroadcastReceiver에서 extra data를 추출해서 Service에서 이용
- 서비스에서 데이터를 액티비티에 전달하는 경우
① Intent에 extra data로 데이터를 담는다
② Intent를 발생시켜서 Activity 내부의 BroadcastReceiver가 실행되도록 한다
③ BroadcastReceiver에서 extra data를 추출해서 Activity에서 이용
bindService
1. bindService
- bindService()는 서비스가 실행되면서 자신을 실행시킨 곳에 객체를 바인딩한다는 의미
- 서비스를 구동시킨 결과를 자신을 실행시킨 곳에다가 객체를 넘겨준다(바인딩한다)
- 서비스를 구동시킨 곳에 객체를 넘겨주고 그 객체에 있는 함수를 호출하면서 매개변수 혹은 리턴값으로 서비스와 서비스를 구동시킨 곳에서 서로 데이터를 주고 받을 수 있음
2. bindService 사용
(1) 서비스의 라이프사이클 함수 중 onBind() 함수가 실행
class MyBinder: Binder() {
fun funA(arg: Int){
}
fun funB(arg: Int): Int{
return arg*arg
}
}
override fun onBind(intent: Intent): IBinder? {
return MyBinder()
}
- Binder를 상속받은 클래스를 준비하고 이 클래스의 객체를 리턴
- Binder를 상속받은 클래스 내부의 함수의 매개변수나 리턴값으로 서비스를 구동시킨 곳과 데이터를 주고 받음
(2) 서비스를 구동시키는 곳
val connection: ServiceConnection = object: ServiceConnection{
override fun onServiceConnected(name: ComponentName?, service: IBinder?){
serviceBinder = service as MyService.MyBinder
}
override fun onServiceDisconnected(name: ComponentName?){
}
}
- ServiceConnection을 구현한 객체 준비
- onServiceConnected() 함수의 매개변수로 서비스에서 보낸 Bind 객체 전달