
서비스는 별도의 사용자 인터페이스를 제공하지 않으면서 백그라운드에서 장시간 작업을 수행하는 애플리케이션 구성 요소이다. 일단 시작된 서비스는 사용자가 다른 앱으로 전환하더라도 실행 상태를 유지할 수 있으며, 다른 구성 요소와 바인딩되어 상호작용하거나 프로세스 간 통신(IPC)을 수행하는 기능을 제공한다. 이를 통해 네트워크 트랜잭션 처리, 음악 재생, 파일 I/O 또는 콘텐츠 제공자와의 상호작용과 같은 복잡한 작업들을 백그라운드에서 효율적으로 처리한다.
서비스는 별도의 설정을 하지 않는 한 호스팅 프로세스의 메인 스레드에서 실행되며 스스로 스레드나 프로세스를 생성하지 않는다. 따라서 시스템이 응답하지 않는 ANR(Application Not Responding) 오류를 방지하려면, 서비스 내의 모든 차단 작업(Blocking operations)을 반드시 별도의 스레드에서 수행해야 한다.
ㅤ

서비스는 독립된 프로세스나 스레드가 아니다. 별도로 지정하지 않는 한 애플리케이션이 속한 동일한 프로세스 내에서 실행된다.
메인 스레드에서 동작하므로 스스로 메인 스레드 외부에서 작업(ANR 방지)을 수행하는 수단이 아니다.
앱이 사용자 상호작용 없이도 백그라운드에서 수행하려는 작업을 시스템에 전달하며, 이는 Context.startService() 호출을 통해 시스템이 작업을 예약하고 명시적으로 중단될 때까지 실행되도록 한다.
앱의 일부 기능을 다른 앱에 노출하며, 이는 Context.bindService()를 통해 서비스와 상호작용할 수 있는 장기적인 연결 통로를 제공한다.
ㅤ

사용자에게 눈에 보이는(Noticeable) 작업을 수행하며, 사용자가 앱과 상호작용하지 않을 때도 계속 실행된다.
반드시 알림(Notification)을 표시하여 사용자가 서비스 실행 사실을 인지하게 해야 하며, 서비스가 중지되거나 포그라운드에서 제거되지 않는 한 이 알림은 사용자가 지울 수 없다.
참고: 유연한 작업 예약을 위해 직접 구현하기보다 WorkManager API를 사용하는 것이 권장되는 경우가 많다.
저장 공간 정리와 같이 사용자가 직접 인식하지 못하는 작업을 수행한다.
참고: API 레벨 26(Android 8.0) 이상에서는 앱이 포그라운드에 있지 않을 때 백그라운드 서비스 실행에 제한(Restrictions)이 따르므로, WorkManager를 사용하여 작업을 예약해야 한다.
bindService() 호출을 통해 애플리케이션 구성 요소가 연결된 상태를 의미하며, 클라이언트-서버 인터페이스를 통해 상호작용 및 프로세스 간 통신(IPC)을 수행한다.
바인드 서비스는 다른 구성 요소가 바인딩되어 있는 동안에만 실행되며, 여러 구성 요소가 동시에 바인딩될 수 있지만 모든 바인딩이 해제되면 서비스는 소멸된다.
서비스는 onStartCommand()와 onBind() 콜백을 각각 구현함으로써 무기한 실행되는 시작 상태와 바인딩 상태를 동시에 가질 수 있다.
기본적으로 모든 구성 요소가 인텐트(Intent)를 통해 서비스를 사용할 수 있지만, 보안을 위해 매니페스트 파일에서 private으로 선언하여 외부 애플리케이션의 접근을 차단할 수 있다.
ㅤ

시스템이 서비스를 실행하는 데에는 두 가지 이유(two reasons)가 존재한다. 누군가 Context.startService()를 호출하면 시스템은 서비스를 검색하여(필요 시 생성 및 onCreate() 호출) 클라이언트가 제공한 인수를 사용하여 onStartCommand() 메서드를 호출한다. 서비스는 Context.stopService() 또는 stopSelf()가 호출될 때까지 계속 실행된다. Context.startService()를 여러 번 호출해도 중첩되지 않지만 여러 번의 onStartCommand() 호출이 발생하며, 단 한 번의 중단 호출로 서비스가 정지된다. 다만, stopSelf(int)를 사용하여 모든 시작 인텐트가 처리되었는지 확인한 후 정지할 수 있다.
시작된 서비스(Started services)는 onStartCommand()에서 반환하는 값에 따라 두 가지 주요 동작 모드로 결정된다. START_STICKY는 명시적으로 시작되고 중단되는 서비스에 사용되는 반면, START_NOT_STICKY 또는 START_REDELIVER_INTENT는 명령을 처리하는 동안에만 유지되어야 하는 서비스에 사용된다.
클라이언트는 Context.bindService()를 사용하여 서비스와 지속적인 연결(persistent connection)을 맺을 수 있다. 이 방식은 서비스를 생성하지만(필요 시 onCreate() 호출) onStartCommand()는 호출하지 않는다. 클라이언트는 onBind() 메서드에서 반환하는 IBinder 객체를 수신하여 서비스와 통신하며, 연결이 수립되어 있는 동안 서비스가 계속 실행된다.
서비스는 시작(Started)됨과 동시에 연결(Bound)될 수 있다. 이 경우 시스템은 서비스가 시작된 상태이거나 하나 이상의 BIND_AUTO_CREATE 플래그를 가진 연결이 있는 한 서비스를 유지한다. 두 조건이 모두 해당되지 않으면 onDestroy()가 호출되며, 서비스가 종료될 때 스레드 중지 및 리시버 등록 해제와 같은 모든 정리 작업(All cleanup)이 완료되어야 한다.
ㅤ

안드로이드 시스템은 서비스가 시작되었거나 클라이언트가 바인딩되어 있는 한, 해당 서비스를 호스팅하는 프로세스를 유지하려고 시도한다. 메모리가 부족하여 프로세스를 종료해야 할 때, 호스팅 프로세스의 우선순위는 다음 가능성 중 가장 높은 것을 기준으로 결정된다.
서비스가 현재 onCreate(), onStartCommand(), 또는 onDestroy() 메서드의 코드를 실행 중인 경우, 시스템은 이 코드가 종료 없이 실행되도록 해당 프로세스를 포그라운드 프로세스(foreground process)로 간주한다.
서비스가 시작된 상태라면, 호스팅 프로세스는 사용자에게 보이는 프로세스보다는 중요도가 낮지만 보이지 않는 프로세스보다는 더 중요하게 취급된다. 다만, 백그라운드 서비스는 사용자가 직접 인식하지 못하므로 종료 후보(candidate to kill)가 될 수 있으며, 특히 장기간 실행될수록 종료 후 재시작될 가능성이 높아진다.
서비스에 바인딩된 클라이언트가 있는 경우, 호스팅 프로세스는 가장 중요한 클라이언트보다 결코 낮지 않은 중요도를 가진다. 예를 들어 클라이언트 중 하나가 사용자에게 보인다면, 서비스 자체도 보이는 상태(visible)로 간주된다.
시작된 서비스가 startForeground() API를 사용하면 서비스는 포그라운드 상태가 된다. 이 경우 시스템은 사용자가 능동적으로 인지하고 있다고 판단하여 극단적인 메모리 압박이 없는 한 종료 후보에서 제외한다.
이러한 메커니즘은 서비스가 실행되는 동안 시스템에 의해 종료될 수 있음을 의미하며, 이 경우 시스템은 나중에 서비스를 다시 시작하려고 시도한다. 따라서 onStartCommand()를 비동기적으로 구현할 때는 인텐트가 유실되지 않도록 START_FLAG_REDELIVERY를 사용하는 것이 중요하다.
ㅤ

서비스에 대한 전역적인 접근은 매니페스트의 service 태그 내 선언을 통해 강제할 수 있으며, 이 경우 다른 애플리케이션이 해당 서비스를 시작, 중지 또는 바인딩하려면 자신의 매니페스트에 대응하는 uses-permission 요소를 반드시 선언해야 한다.
또한 Context.startService(Intent)를 호출할 때 인텐트에 FLAG_GRANT_READ_URI_PERMISSION 또는 FLAG_GRANT_WRITE_URI_PERMISSION 플래그를 설정할 수 있다. 이를 통해 서비스에 인텐트에 포함된 특정 URI에 대한 임시 접근 권한을 부여할 수 있으며, 이 권한은 서비스가 해당 명령에 대해 stopSelf(int)를 호출하거나 완전히 중단될 때까지 유지된다. 이러한 방식은 서비스가 외부로 노출(exported)되지 않은 상태에서도 다른 앱에 권한을 부여하는 수단으로 활용된다.
추가적으로, 서비스는 실제 구현 로직을 실행하기 전에 checkCallingPermission(String) 메서드를 호출함으로써 개별적인 IPC 호출 자체를 권한으로 보호할 수 있다.
ㅤ

서비스는 사용자가 앱과 상호작용하지 않을 때도 작업이 지속되어야 할 때만 생성해야 한다.
앱이 포그라운드에 있을 때만 메인 스레드 밖에서 작업을 수행해야 한다면 코틀린 코루틴이나 새로운 스레드를 사용하는 것이 적절하다. 서비스를 사용하더라도 기본적으로 메인 스레드에서 실행되므로 집약적인 작업 시 서비스 내부에 별도의 스레드를 직접 생성해야 한다.
ㅤ

서비스를 생성하려면 Service의 서브클래스를 생성해야 하며, 수명 주기의 핵심 측면을 처리하는 콜백 메서드를 오버라이드하고 적절한 경우 구성 요소가 서비스에 바인딩할 수 있는 메커니즘을 제공해야 한다. 다음은 오버라이드해야 할 가장 중요한 콜백 메서드들이다.
시스템(Android Linux System)은 다른 구성 요소가 startService()를 호출하여 서비스 시작을 요청할 때 이 메서드를 호출한다. 이 메서드가 실행되면 서비스가 시작되어 백그라운드에서 무기한(indefinitely) 실행될 수 있으며, 작업이 완료되었을 때 stopSelf() 또는 stopService()를 호출하여 서비스를 중단하는 것은 개발자의 책임이다.
다른 구성 요소가 bindService()를 호출하여 서비스와 바인딩하고자 할 때 시스템이 이 메서드를 호출한다. 이 메서드 구현 시 클라이언트가 서비스와 통신하는 데 사용할 IBinder 인터페이스를 반환해야 하며, 바인딩을 허용하지 않으려면 null을 반환해야 한다.
서비스가 처음 생성될 때(initially created) onStartCommand() 또는 onBind() 호출 직전에 수행되는 일회성 설정 절차이다. 서비스가 이미 실행 중인 경우에는 호출되지 않는다.
서비스가 더 이상 사용되지 않고 소멸될 때 시스템이 호출하는 마지막 콜백이다. 이 메서드에서 스레드, 등록된 리스너 또는 리시버와 같은 모든 리소스를 정리(clean up)해야 한다.
구성 요소가 startService()를 호출하여 서비스를 시작하면 서비스는 stopSelf() 또는 다른 구성 요소가 stopService()를 호출할 때까지 계속 실행된다. 반면 bindService()를 통해 생성된 경우 onStartCommand()는 호출되지 않으며, 서비스는 해당 구성 요소가 바인딩되어 있는 동안에만 실행된다. 모든 클라이언트가 바인딩을 해제하면 시스템이 서비스를 소멸시킨다.
안드로이드 시스템은 메모리가 부족할 때만(only when memory is low) 서비스를 강제로 중단하며, 사용자가 집중하고 있는 액티비티에 바인딩된 서비스는 종료될 가능성이 낮다. 서비스가 포그라운드에서 실행되도록 선언된 경우에도 거의 종료되지 않지만, 시작된 상태로 오래 지속되는 백그라운드 서비스는 시간이 지남에 따라 우선순위가 낮아져 종료 후보가 되기 쉽다. 시스템에 의해 서비스가 종료되더라도 자원이 확보되면 다시 시작되며, 이는 onStartCommand()의 반환 값에 따라 달라진다.
ㅤ


액티비티 및 기타 구성 요소와 마찬가지로 애플리케이션의 모든 서비스는 매니페스트 파일에 선언해야 한다.
서비스를 선언하려면 application 요소의 자식 요소로 service 요소를 추가해야 한다.
서비스를 시작하는 데 필요한 권한이나 서비스가 실행되어야 하는 프로세스와 같은 속성을 정의하기 위해 기타 속성들을 service 요소에 포함할 수 있다.
android:name 속성은 유일한 필수 속성이며 서비스의 클래스 이름을 지정한다.
애플리케이션을 게시한 후에는 서비스를 시작하거나 바인딩하기 위한 명시적 인텐트(explicit intents)에 대한 의존성으로 인해 코드가 망가질 위험을 방지하기 위해 이 이름을 변경하지 않고 유지해야 한다.
caution : 앱의 보안을 보장하기 위해 서비스를 시작할 때는 항상 명시적(explicit) 인텐트를 사용해야 하며, 서비스에 대한 인텐트 필터를 선언하지 않아야 한다. 암시적 인텐트를 사용하여 서비스를 시작하는 것은 어떤 서비스가 인텐트에 응답할지 확신할 수 없고 사용자가 어떤 서비스가 시작되는지 확인할 수 없기 때문에 보안상 위험(security hazard)이다. 안드로이드 5.0(API 레벨 21)부터 시스템은 암시적 인텐트로 bindService()를 호출할 경우 예외(exception)를 발생시킨다.
매니페스트에 android:exported 속성을 포함하고 false로 설정하면 서비스가 자신의 앱에서만 사용되도록 보장할 수 있다. 이 설정은 명시적 인텐트를 사용하는 경우에도 다른 앱이 해당 서비스를 시작하는 것을 효과적으로 차단한다.
사용자는 기기에서 어떤 서비스가 실행 중인지 확인할 수 있으며, 인식하지 못하거나 신뢰할 수 없는 서비스는 직접 중지할 수 있다. 사용자가 실수로 서비스를 중단하는 것을 방지하려면 앱 매니페스트의 service 요소에 android:description 속성을 추가해야 한다. 설명문에는 서비스가 수행하는 작업과 이를 통해 제공되는 이점을 설명하는 짧은 문장을 제공해야 한다.
ㅤ

시작된 서비스(Started service)는 다른 앱 구성 요소가 startService()를 호출할 때 시작되며, 이는 서비스의 onStartCommand() 메서드 호출로 이어진다. 서비스가 시작되면 이를 호출한 구성 요소와 독립적인 수명 주기를 갖게 되며, 자신을 실행시킨 구성 요소가 파괴되더라도 백그라운드에서 무기한으로 실행될 수 있다. 따라서 작업이 완료되었을 때 서비스가 stopSelf()를 호출하여 스스로 중단하거나, 다른 구성 요소가 stopService()를 호출하여 중단시켜야 한다.
액티비티와 같은 구성 요소는 서비스를 시작하면서 인텐트(Intent)를 전달할 수 있으며, 서비스는 onStartCommand() 내에서 이 인텐트를 수신하여 작업을 수행한다. 예를 들어, 온라인 데이터베이스에 데이터를 저장하는 작업을 수행한 후 작업이 완료되면 서비스가 스스로 중단되고 소멸되는 방식이 이에 해당한다.
Caution : 서비스는 기본적으로 선언된 애플리케이션과 동일한 프로세스에서 실행되며, 해당 애플리케이션의 메인 스레드를 사용한다. 만약 서비스가 사용자와 상호작용 중인 액티비티가 있는 상황에서 집약적이거나 차단 작업(intensive or blocking operations)을 수행하면 앱의 성능이 저하될 수 있다. 이를 방지하기 위해 반드시 서비스 내부에 새로운 스레드를 시작하여 작업을 수행해야 한다.
Service 클래스는 모든 서비스의 기본 클래스이며, 모든 작업을 메인 스레드에서 수행하므로 앱 성능 저하를 방지하기 위해 별도의 스레드 생성이 중요하다.
워커 스레드에서 요청을 하나씩 처리하던 IntentService는 안드로이드 8.0의 백그라운드 실행 제한으로 인해 더 이상 권장되지 않으며 사용이 중단(deprecated)되었다. 최신 버전에서는 JobIntentService를 사용하거나, 대부분의 유스케이스에서 권장되는 WorkManager를 사용하는 것이 적절하다.
ㅤ




서비스를 확장하는 것은 각 수신 인텐트를 직접 처리할 수 있는 가장 기본적인 구현 방식이다. 서비스는 기본적으로 애플리케이션의 메인 스레드에서 실행되므로, UI 작업을 방해하지 않기 위해 백그라운드 스레드(예: HandlerThread)를 생성하여 작업을 수행해야 한다.
서비스가 처음 생성될 때 단 한 번 호출되는 콜백으로, 작업을 수행할 백그라운드 스레드(HandlerThread)를 시작하고 이를 관리할 핸들러(Handler)를 설정하는 초기화 과정을 수행한다.
다른 구성 요소가 startService()를 호출할 때마다 실행되며, 각 요청에 대해 핸들러에 메시지를 전달하여 작업을 예약한다. 이 메서드는 시스템이 서비스를 종료했을 때의 복구 방식을 결정하는 정수값(Return Constant)을 반환해야 한다.
핸들러 내부의 handleMessage() 메서드에서 실제 비즈니스 로직(파일 다운로드 등)을 처리하며, 모든 요청은 순차적으로(serially) 처리된다. 작업이 완료되면 stopSelf(startId)를 호출하여 다른 대기 중인 요청이 없을 때만 서비스를 안전하게 종료하도록 관리해야 한다.
바인딩 기능을 제공하지 않는 서비스의 경우 반드시 null을 반환하도록 구현해야 한다.
onStartCommand()의 반환 값은 시스템이 메모리 부족으로 서비스를 강제 종료한 후 다시 시작할 방법을 정의한다.
START_STICKY : 시스템이 서비스를 강제로 종료한 후 서비스를 재생성하지만, 마지막 인텐트를 다시 전달하지는 않고 null 인텐트로 호출한다. 이는 음악 플레이어처럼 무기한 실행되면서 작업을 기다리는 서비스에 적합하다.
START_NOT_STICKY : 시스템이 서비스를 종료한 후, 대기 중인 새로운 인텐트가 없다면 서비스를 재생성하지 않는다. 이는 가장 안전한 옵션이며 앱이 미완성 작업을 쉽게 재시작할 수 있을 때 유용하다.
START_REDELIVER_INTENT : 시스템이 서비스를 재생성하면서 마지막으로 전달되었던 인텐트를 다시 전달한다. 파일 다운로드처럼 즉시 재개해야 하는 작업에 적합하다.
ㅤ

서비스를 시작하려면 액티비티나 다른 구성 요소에서 인텐트(Intent)를 startService() 또는 startForegroundService()에 전달해야 하며, 시스템은 서비스의 onStartCommand() 메서드를 호출하고 해당 인텐트를 전달한다. API 레벨 26 이상에서는 앱이 포그라운드에 있지 않을 때 백그라운드 서비스를 생성하거나 사용하는 데 제한이 있으므로, 시스템에 포그라운드 서비스를 만들겠다는 신호를 보내는 startForegroundService()를 호출해야 하며 서비스 생성 후 5초 이내에 startForeground()를 호출해야 한다.
startService() 메서드는 즉시 반환되며, 서비스가 아직 실행 중이 아니라면 시스템은 먼저 onCreate()를 호출한 다음 onStartCommand()를 호출한다. 바인딩을 제공하지 않는 서비스의 경우 전달된 인텐트가 유일한 통신 수단이지만, 결과를 돌려받고 싶다면 클라이언트가 브로드캐스트(getBroadcast())를 위한 PendingIntent를 생성하여 서비스에 전달하고 서비스가 이를 사용하여 결과를 전송할 수 있다. 서비스를 시작하라는 요청이 여러 번 발생하면 여러 번의 onStartCommand() 호출이 이루어지지만, 서비스를 중단하는 데에는 단 한 번의 stopSelf() 또는 stopService() 호출만이 필요하다.
ㅤ
시작된 서비스는 스스로 자신의 수명 주기를 관리해야 하며, 시스템은 메모리 회수가 필요한 경우가 아니면 onStartCommand()가 반환된 후에도 서비스를 중단하거나 파괴하지 않는다. 그러므로 서비스는 stopSelf()를 호출하여 스스로 중단하거나, 다른 구성 요소가 stopService()를 호출하여 중단시켜야 한다.
stopSelf() 또는 stopService()를 통해 중단 요청이 접수되면, 시스템은 가능한 한 빨리 서비스를 파괴한다.
만약 서비스가 여러 개의 onStartCommand() 요청을 동시에 처리한다면, 새로운 시작 요청을 받았을 때 서비스가 종료되는 문제를 방지하기 위해 작업이 끝났다고 해서 즉시 서비스를 중단해서는 안 된다. 이 문제를 해결하기 위해 stopSelf(int)를 사용할 수 있으며, 이는 중단 요청이 가장 최근의 시작 요청(startId)에 해당할 때만 서비스를 종료하도록 보장한다. 만약 stopSelf(int)를 호출하기 전에 새로운 시작 요청을 받으면 ID가 일치하지 않아 서비스는 중단되지 않는다.
Caution : 시스템 자원 낭비와 배터리 소모를 방지하기 위해 작업이 완료된 서비스는 반드시 중단해야 한다. 서비스에 바인딩을 허용했더라도 onStartCommand() 호출을 한 번이라도 받았다면 개발자가 직접 서비스를 중단해야 한다는 점에 유의해야 한다.
ㅤ

바운드 서비스는 애플리케이션 구성 요소가 bindService()를 호출하여 서비스와 지속적인 연결(long-standing connection)을 생성할 수 있도록 허용하는 서비스이다. 이러한 서비스는 일반적으로 구성 요소가 startService()를 호출하여 직접 시작하는 것을 허용하지 않으며, 주로 액티비티나 다른 구성 요소와 상호작용하거나 프로세스 간 통신(IPC)을 통해 앱의 기능을 외부로 노출하려는 목적으로 생성한다. 이를 구현하기 위해서는 서비스와 클라이언트 간의 통신 인터페이스를 정의하는 onBind() 콜백 메서드를 반드시 구현해야 하며, 이 메서드는 클라이언트가 서비스의 메서드를 호출하는 데 사용할 IBinder 객체를 반환해야 한다. 클라이언트는 이 인터페이스를 수신한 뒤 서비스와 상호작용을 시작할 수 있다.
바운드 서비스는 자신에게 바인딩된 애플리케이션 구성 요소에 서비스를 제공하기 위해서만 존재하기 때문에, 연결된 구성 요소가 하나도 남지 않게 되면 시스템에 의해 자동으로 소멸된다. 따라서 onStartCommand()를 통해 시작된 서비스와 달리 개발자가 별도의 중단 절차(stopSelf 등)를 거칠 필요가 없다. 서비스에는 여러 클라이언트가 동시에 바인딩할 수 있으며, 클라이언트는 상호작용이 완료되면 unbindService()를 호출하여 바인딩을 해제한다. 서비스에 바인딩된 클라이언트가 단 하나도 남지 않는 즉시 시스템은 서비스를 파괴한다. 바운드 서비스는 구현 방식이 시작된 서비스보다 더 복잡하므로, 상황에 따라 Binder 확장, Messenger 사용 또는 AIDL 정의 중 적절한 방식을 선택해야 한다.
ㅤ

서비스의 수명 주기는 액티비티보다 훨씬 단순하지만, 사용자가 인지하지 못하는 백그라운드에서 실행될 수 있으므로 서비스가 생성되고 파괴되는 방식에 세심한 주의를 기울이는 것이 더욱 중요하다. 서비스의 수명 주기는 생성부터 소멸까지 다음 두 가지 경로 중 하나를 따를 수 있다.
다른 구성 요소가 startService()를 호출할 때 서비스가 생성된다. 서비스는 무기한으로 실행되며, 서비스 스스로 stopSelf()를 호출하거나 다른 구성 요소가 stopService()를 호출하여 중단시켜야 한다. 서비스가 중단되면 시스템은 이를 소멸시킨다.
클라이언트가 bindService()를 호출할 때 서비스가 생성된다. 클라이언트는 IBinder 인터페이스를 통해 서비스와 통신하고 unbindService()를 호출하여 연결을 종료할 수 있다. 여러 클라이언트가 동일한 서비스에 바인딩될 수 있으며, 모든 클라이언트가 바인딩을 해제하면 시스템이 서비스를 소멸시킨다. 이 경우 서비스는 스스로 중단될 필요가 없다.
이 두 경로는 완전히 분리된 것이 아니며, 이미 startService()로 시작된 서비스에 바인딩하는 것도 가능하다. 예를 들어 인텐트를 통해 재생할 음악을 식별하여 음악 서비스를 시작한 후, 나중에 사용자가 플레이어를 제어하거나 현재 곡 정보를 얻고자 할 때 액티비티가 해당 서비스에 바인딩할 수 있다. 이러한 경우 모든 클라이언트가 바인딩을 해제할 때까지 stopService()나 stopSelf()를 호출해도 서비스가 실제로 중단되지 않는다.
ㅤ



액티비티와 마찬가지로 서비스는 상태 변화를 모니터링하고 적절한 시점에 작업을 수행할 수 있는 수명 주기 콜백 메서드를 제공한다. 모든 서비스는 시작 방식과 관계없이 onCreate()와 onDestroy() 메서드를 공통적으로 호출받으며, 이를 통해 초기 설정과 자원 해제를 관리한다.
서비스가 처음 생성될 때 호출되며, 이곳에서 스레드 생성이나 초기화와 같은 초기 설정 절차를 수행한다.
startService() 호출에 의해 서비스가 시작될 때 실행되며, 서비스가 종료되었을 때 어떻게 재시작할지를 결정하는 시작 모드(startMode) 정수를 반환한다.
bindService()를 통해 클라이언트가 바인딩될 때 호출되며, 클라이언트가 서비스와 상호작용할 수 있는 IBinder 인터페이스를 반환한다.
모든 클라이언트가 unbindService()를 호출하여 연결을 해제했을 때 실행되며, 이후 새로운 클라이언트가 바인딩될 때 onRebind() 호출 여부를 결정하는 불리언 값을 반환한다.
onUnbind()가 이미 호출된 상태에서 새로운 클라이언트가 서비스에 연결될 때 호출된다.
서비스가 더 이상 사용되지 않고 소멸될 때 호출되는 마지막 메서드로, 사용 중이던 모든 리소스(스레드, 리스너 등)를 해제해야 한다.
onCreate() 호출 시점부터 onDestroy()가 반환되는 시점 사이의 기간을 의미한다. 서비스는 onCreate()에서 초기 설정을 완료하고 onDestroy()에서 남은 모든 자원을 해제한다.
Started service 의 경우 onStartCommand() 호출과 함께 시작되어 전체 생존 기간이 끝날 때까지 유지되며, Bound service 는 onBind() 호출 시작되어 onUnbind()가 반환될 때 종료된다.
ㅤ