목 차
1. 안드로이드 : Service란 ?
2. Service의 종류 : Foreground / Background / Bound
3. Service의 형태 : Started / Bound
4. Service Lifecycle & 콜백함수
◇ 안드로이드 4대 컴포넌트 중 하나로 "백그라운드 업무"를 담당하기 위한 컴포넌트.
√ Activity처럼 사용자와 상호작용하는 컴포넌트가 아닌,
백 그라운드에서 오랜 시간 동안 수행되는 업무를 처리하기 위한 컴포넌트.
√ 사용자에게 인터페이스를 제공하지 않고, 백그라운드에서 오래 실행되는 작업을 수행할 수 있는 애플리케이션 구성 요소.
ex) 파일 다운로드, 데이터 체크, 데이터 처리, 네트워크 트랜잭션, 음악 재생, Content Provicder와의 상호작용 등등..
√ 액티비티가 종료되어 있는 상태(다른앱으로 전환)에서도 동작하기 위해 만들어진 컴포넌트.
ex) 화면이 종료된 상태에서도 노래 재생.
※ 서비스가 실행되고 있는 상태라면, 안드로이드 OS에서는 해당 프로세스를 웬만한 경우에 죽이지 않고 관리합니다.
메모리 부족 등의 특별한 경우를 제외하고 백그라운드 동작으로 수행하도록 설계됨.
- 서비스의 실행은 액티비티와 같이 다른 컴포넌트에서 startService() 메소드 호출에 의해 이루어집니다.
- 서비스는 자신을 실행시킨 컴포넌트와는 독립적인 Life Cycle 을 가집니다.
백그라운드에서 독립적으로 실행 가능(자신을 실행시킨 컴포넌트가 더 이상 존재하지 않아도!)
-> 자신이 stopSelf()를 호출하거나, 다른 컴포넌트가 stopService()를 호출해서 중단해야 함
- 서비스는 필요한 경우,
사용할 Intent 를 넘겨 받을 수 있음 -> startService() 를 호출하며 Intent를 전달합니다.
-> 넘겨 받은 Intent는 onStartCommand() 메소드에서 핸들링 가능합니다.
1) "사용자"와 상호작용 불가.
2) Activity의 생명주기에 종속되어 있지 않습니다.
3) 별도의 스레드에서 동작하지 않습니다. 즉 호스팅 프로세스의 '메인 스레드'에서 작동합니다.
- 안드로이는 프레임워크단이 Linux로 구현되어 있는 Linux 기반의 프로그램이고, 메모리 관리 또한 Linux Kernel에서 해준다.
- 주의할 점은, 모든 컴포넌트들이 Main Thread(UI 작업을 처리해주는 Thread) 안에서 실행된다는 것
-> 서비스 역시 Main Thread에서 관리하므로,
Thread 작업이 필요한 경우에는 작업 Thread 를 생성해서 관리해야 함
-> 그렇지 않으면, ANR(Activity Not Response)가 발생하여 종료되는 문제 발생
4) 현재 비-활성화된, 액티비티보다 우선순위가 높습니다.
◎ Foreground Service
1) Foreground Service는 서비스가 수행하는 동작을 사용자에게 알릴 때 사용합니다.
==> 사용자에게 Notification을 통해서 서비스가 실행되고 있음을 알려야 합니다.
Ex) 음악 플레이어의 경우, 현재 실행중인 음악 등의 정보를 Notification 을 통해 알려주도록 함!
이 Notification은 서비스가 중단되거나 Foreground 에서 제거되지 않는 이상 지울 수 없습니다.
++ 대부분의 경우, WorkManager(Jetpack에 있는 API)를 사용하는 것이,
Foreground Service 를 직접 사용하는 것 보다 낫다고 한다.
2) Foreground Service 는 활성화된 액티비티와 동일한 우선순위를 가진다.
- 따라서, 시스템에 메모리가 부족하더라고 Android System에 의해 종료될 확률이 낮다.
◎ Background Service
1) 사용자에게 보이지 않는 백그라운드 작업 수행
2) 시스템 리소스가 부족할 경우 강제 종료 가능
-> 따라서, 즉각적인 실행을 요구하는 작업에는 포그라운드 서비스를,
예약된 작업일 경우에는 알람매니저나 워크 매니저를 활용해야 합니다.
◎ Bound Service
1) bound service 는 IBinder 라는 인터페이스로 서버-클라이언트 관계처럼 서비스와 상호작용
여러 프로세스에서 같은 서비스에 바인딩하여 작업 수행 가능
-> 여러 프로세스에 걸쳐 프로세스 간 통신(IPC, Interprocess communication)을 수행할 수 있음
2) Bind Service는 여기에 바인딩된 컴포넌트들이 전부 바인딩 해제되면, 서비스가 소멸됨
- startService()를 호출하여 시작됩니다.
- 서비스가 한 번 시작되면 -> 백그라운드에서 무한정 실행됩니다.
- bindService()를 호출하여 시작합니다.
- 서비스가 액티비티와 연결되어 있는 동안에만 실행되고, 액티비티가 사라지면 서비스도 동시에 소멸됩니다.
- startService()로 무한히 실행하게 하고,
- bindService()를 통해 앱의 구성요소에서 통신이 가능합니다.
-> 이 경우, 모든 구성 요소에서 바인드가 해제되더라도 서비스가 종료되지 않음!
-> 반드시 stopService() 혹은 stopSelf()를 통해 서비스를 종료시켜야 함.!
class MyService : Service() {
override fun onBind(intent: Intent): IBinder? {
return null
}
}
Service 를 상속 받아 작성
onBind() 함수는 내부를 구현하지 않더라도 반드시 오버라이드 받아야 한다.
서비스도 컴포넌트이기 때문에 등록해 주어야 합니다.
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"></service>
service 태그로 등록하며 name 속성은 생략 불가
val intent = Intent(this, MyService::class.java)
startService(intent)
startService() 에 의한 실행
외부 앱의 서비스라면 setPackage() 함수를 이용해 실행하고자 하는 앱의 패키지명(식별자) 을 명시
4개의 컴포넌트 중에 유일하게 서비스만 종료하기 위한 인텐트 함수도 존재합니다.
❓ 제공하는 이유는
서비스는 한 번 구동되면 대부분 작업 시간이 길고,
화면 반응성이 없어 유저에 의해 종료될 수 없기 때문입니다.
val intent = Intent(this, MyService::class.java)
stopService(intent)
만약, bindService()를 통해 서비스를 생성했다면,
즉, onStartCommand()를 호출하지 않았으면 바인딩된 서비스가 종료되면 -> 시스템에서 서비스를 제거함
안드로이드는, 디바이스에 메모리가 부족할 때 -> 서비스를 종료해서 -> 시스템 디바이스 자원을 회복한다.
서비스가 백그라운드에서 오래 실행될수록 시스템에 의해 서비스가 종료되기 쉽다.
만약, 시스템이 자원을 확보하기 위해 서비스를 죽이면 -> 서비스를 다시 실행할 수 있는 자원이 확보되는 경우 onStartCommand() 를 다시 실행한다.
-> 그 이후에는 StartCommand()가 호출 됩니다.
-> 서비스를 종료하기 위해서는 stopService()를 실행하거나 / 서비스 자체에서 stopSelf() 를 실행합니다.
-> 그러면, onDestroy()가 호출되어 서비스가 종료 됩니다.
- 비동기 처리에 용이
A. 전달된 인텐트는 작업을 위한 큐에 순차적으로 쌓이고
B. 루퍼에 의해 차례대로 onHandleIntent() 에 전달된다.
C. onHandleIntent()에서 작업이 완료되면 서비스를 종료함
D. 별도의 멀티 스레딩 처리를 고민하지 않아도 된다.