액티비티 컴포넌트, 브로드캐스트 리시버 컴포넌트에 이어 세번째 컴포넌트를 알아보자.
서비스는 오래 걸리는 작업을 백그라운드에서 처리할 수 있게 해 주는 컴포넌트이다. 따라서 서비스에 화면을 구현하지는 않는다. 그리고 서비스 역시 안드로이드의 컴포넌트이므로 생명주기를 시스템에서 관리한다.
서비스 생성과 실행
서비스 컴포넌트는 Service 클래스를 상속받아서 작성한다. 서비스에는 다양한 생명주기 함수를 재정의할 수 있지만 onBind()는 필수이다.
// 서비스 컴포넌트 생성
class MyService : Service() { // 서비스 컴포넌트 위해 서비스 클래스 상속받고
override fun onBind(intent: Intent): IBinder? { // 필수인 onBind() 생명주기 함수 재정의
return null
}
}
서비스도 컴포넌트이므로 매니페스트에 등록해야 한다.
// 서비스 컴포넌트 등록
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"></service>
서비스는 매니페스트에 <service>태그로 등록해야 하며 이때 name 속성은 필수이다. 그리고 명시적 인텐트로 실행하려면 클래스명만 등록하고, 암시적 인텐트로 실행하려면 <intent-filter>등록해야함! 서비스 실행 위해선 시스템에 인텐트를 전달해야 하는데 이때 함수 startService() 와 bindService() 두가지 사용!
두 함수의 차이를 알아보자~
startService() 함수로 실행
startService() 함수로 서비스를 실행하려면 해당 서비스를 인텐트에 담아서 매개변수로 전달해야 한다.
// 서비스 실행
val intent = Intent(this, MyService::class.java) // 서비스 컴포넌트 실행 위한 인텐트 객체 생성
startService(intent) // startService() 함수로 인텐트를 매개변수로 전달하여 등록
만약 📌외부 앱의 서비스라면 암시적 인텐트로 실행해야 하므로 setPackage() 함수를 이용해 앱의 패키지명을 명시해 준다. 그런데 외부 앱이 백그라운드 상태라면 서비스를 실행할 수 없다. 나중에 자세히~
// 암시적 인텐트로 실행
val intent = Intent("ACTION_OUTER_SERVICE")
intent.setPackage("com.example.test_outter") // setPackage() 함술 앱의 패키지명 명시
startService(intent)
서비스는 다른 컴포넌트와 다르게 실행 중인 서비스를 종료하는 함수도 제공한다. 서비스를 종료하려면 stopService() 함수로 인텐트를 전달해야 한다.
// 서비스 종료
val intent = Intent(this, MyService::class.java) // 서비스 컴포넌트 종료 위한 인텐트 생성
stopService(intent) // 함수 stopService()에 인텐트를 매개변수로 담아 시스템에 전달
bindService() 함수로 실행
서비스를 실행하는 또 다른 함수는 bindService() 이다. 이 함수로 서비스를 실행하려면 먼저 ServiceConnection 인터페이스를 구현한 객체를 준비해야 한다.
// ServiceConnection 인터페이스 구현
val connection: ServiceConnection = object : ServiceConnection { // 필요 인터페이스를 구현한 객체를 생성
override fun onServiceConnected(name: ComponentName?, service: IBinder?) { }
// bindService() 함수로 서비스 구동할 때 자동 호출됨
override fun onServiceDisconnected(name: componentName?) {}
// unbindService() 함수로 서비스 종료할 때 자동 호출됨
}
ServiceConnection 인터페이스에는 추상 함수가 2개 정의되어 있다. 따라서 onServiceConnected()와 onServiceDisconnected() 함수를 재정의해야 하는데 onServiceConnected()는 bindService() 함수로 서비스를 구동할 때 자동으로 호출되며, onServiceDisconnected()는 unbindService()함수로 서비스를 종료할 때 자동으로 호출된다.
이렇게 1️⃣ServiceConnection을 구현한 객체를 준비한 후 2️⃣bindService() 함수로 인텐트를 시스템에 전달해 서비스를 실행한다. 만약 bindService()로 실행할 서비스가 📌외부 앱의 것이라면 setPackage()함수로 패키지명을 명시해야 한다.
// 서비스 실행
val intent = Intent(this, MyService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
// bindService() 함수로 인텐트를 시스템에 전달해 서비스 실행함
bindService() 함수는 매개변수가 3개이다. ①첫 번째는 인텐트 객체이며 ②두 번째가 ServiceConnection을 구현한 객체이다. 두 번째 매개변수는 서비스를 실행하거나 종료할 때 이 객체의 onServiceConnected()나 onServiceDisconnected() 함수가 자동으로 호출된다. 그리고 ③세 번째 매개변수는 Int 타입의 flags인데 이 값은 대부분 Context.BIND_AUTO_CREATE로 지정한다. 이는 서비스가 실행 상태가 아니더라도 객체를 생성해서 실행하라는 의미이다. 만약 Context.BIND_AUTO_CREATE를 지정하지 않으면 bindService() 함수로 인텐트를 전달해도 서비스가 실행 상태가 아니면 동작하지 않는다.
bindService() 함수로 실행한 서비스는 unbindSerivce() 함수로 종료할 수 있다.
// 서비스 종료
unbindService(connection)
// unbindService 함수에 ServiceConnection을 구현한 객체인 connection을 담아 시스템에 전달하여 서비스 종료
서비스 생명주기
서비스를 실행하는 2가지 방법은 startService()와 bindService()이므로 어느 함수를 이용해 서비스를 실행하는지에 따라 생명주기가 나뉜다.
바인딩되지 않은 서비스 생명주기 | (서비스의 생명주기 나타낸 표) | 바인딩된 서비스 생명주기 |
startService() 함수 호출 | bindService() 함수 호출 | |
onCreate() | 생명주기 활성 |
onCreate() |
onStartCommand() | onBind() | |
서비스 실행 | 클라이언트를 서비스에 바인딩 | |
스스로 또는 클라이언트가 서비스 중단 | 모든 클라이언트가 unBindService() 함수로 바인딩 해제 | |
onUnbind() | ||
onDestroy() | onDestroy() | |
서비스 종료 | 서비스 종료 |
startService() 함수에서 서비스 객체를 생성하면 onCreate()→onStartCommand() 함수가 호출되고 서비스가 실행된다. 이 상태에서 다시 startService() 함수를 호출하면 서비스 객체가 다시 생성되지 않고 onStartCommand() 함수만 다시 호출된다. 결국 onCreate() 함수는 서비스 객체가 생성될 때 처음에 한 번만 호출되며, onStartCommand() 함수는 startService() 함수가 실행될 때마다 반복해서 호출된다. 그리고 stopService() 함수로 서비스가 종료되면 바로 전에 onDestroy() 함수가 호출된다.
bindService() 함수에서 서비스 객체를 생성하면 onCreate→onBind() 함수가 호출되고 서비스가 실행된다. bindService() 함수로 실행된 서비스를 다시 bindService() 함수로 실행하면 onBind() 함수만 다시 호출된다. 그리고 unbindService() 함수로 서비스를 종료하면 onUnbind()→onDestroy() 함수까지 실행된다.
정리
서비스컴포넌트도 다른 컴포넌트와 같이 시스템에 인텐트를 전달해서 사용한다. 그런데 이때 사용하는 함수가 두가지가 있고 어떤 함수를 사용하는지에 따라 생명주기를 관리하는 함수가 달라진다. startService()로 서비스를 실행할 때와 달리 bindService()를 이용할 때는 인텐트 객체 말고도 특정 인터페이스를 구현한 객체를 준비해야하고 서비스가 실행 상태가 아니더라도 객체를 생성해서 실행하도록 하는 기능도 있다.
공부일기
피곤했는가봐 당충전해서 식곤증온건가? 도서관에서 1시간 자버림... ㅋㅋ 오늘 내일 해서 이론 끝내는게 환상적!!!!
'깡샘 코틀린' 카테고리의 다른 글
15-3 백그라운드 제약 (0) | 2023.07.07 |
---|---|
15-2 바인딩 서비스 (0) | 2023.07.07 |
14-2 시스템 상태 파악하기 (0) | 2023.07.03 |
14-1 브로드캐스트 리시버 이해하기 (0) | 2023.07.03 |
섹션 0. 들어가기에 앞서 (0) | 2023.07.02 |