본문 바로가기
프로그래밍/Android

안드로이드 서비스 (1)

by Daniel.kwak 2019. 2. 18.

서비스

서비스는 백그라운드에서 오래 실행되는 작업을 수행하는 애플리케이션 구성요소이며 사용자 인터페이스를 제공하지 않습니다. 다른 구성요소(액티비티 같은)가 서비스를 시작할 수 있으며 사용자가 다른 애플리케이션으로 전환하더라도 계속 실행된다. 이 외에도 앱의 구성요소를 서비스에 바인드하여 상호작용 할 수 있다. 서비스의 예로는 네트워크 트랜잭션을 처리하고, 음악을 재생하고, I/O를 처리하며 ContentsProvider와 상호작용할 수 있고 이 모든 작업을 백그라운드에서 실행할 수 있다. 


서비스는 두 가지 형태가 있다.


-시작됨

애플리케이션의 구성요소(예:액티비티)가 startService()를 호출하여 서비스를 시작한다. 서비스는 한 번 시작되면 백그라운드에서 무기한 실행될 수 있으며, 호출한 구성요소가 소멸되어도 지속된다. 보통, '시작된' 서비스는 네트워크로 파일을 다운로드 하거나 업로드 하는것과 같이 수행 결과를 반환하지 않고 작업을 완료하면 자연스럽게 소멸된다. 


-바인드됨

애플리케이션 구성요소가 bindService()를 호출하여 해당 서비스에 바인드되면 서비스가 "바인드"된다. 바인드된 서비스는 클라이언트-서버 인터페이스를 제공하며 구성요소가 서비스와 상호작용을 할 수 있도록 하며, 결과를 가져올 수 있다. 심지어 여러 프로세스에 걸쳐 IPC로 수행할 수도 있다. 바인드된 서비스는 애플리케이션 구성요소가 서비스에 바인드 되어 있는 경우에만 실행된다. 여러 구성요소가 동시에 서비스에 바인드 될 수 있다.


애플리케이션의 모든 구성요소가 서비스를 intent로 시작할 수 있다.(다른 애플리케이션도) 매니페스트에서 서비스를 비공개로 돌릴수도 있다. 


*서비스는 본인의 쓰레드를 생성하지 않으며 별도의 프로세스에서 실행되지도 않는다. 자신의 호스팅 프로세스의 기본 스레드에서 실행된다. 따라서 서비스 또한 ANR을 방지하기 위해서 별도의 쓰레드를 생성해야 함을 뜻한다. 


*서비스와 쓰레드중 어떤 것을 사용해야 할까?

서비스는 사용자와 상호작용하지 않는 백그라운드에서 실행될 수 있는 구성요소일 뿐, 서비스의 목적은 이에 국한되어야 한다. 

기본 쓰레드 외부에서 작업을 수행해야 하지만, 사용자가 애플리케이션과 상호작용일 때만 수행되어야 한다면 서비스가 아니라 쓰레드가 적합하다. (예: 액티비티가 실행되는 중에만 음악을 재생하고 싶으면 onCreate에서 쓰레드를 생성하고, onStart에서 쓰레드를 시작, onStop에서 쓰레드를 중지하면 된다. 



기본사항

서비스를 생성하려면 Service를 상속받는 서브 클래스를 만들면 된다. 중요한 오버라이드 메소드를 보자.


onStartCommand()

이 메소드는 다른 구성요소가 서비스를 startService()로 시작한 경우 호출된다. 이 메소드가 실행되면 서비스가 무기한 실행될 수 있다. 그러나 이 메소드를 구현하면 서비스를 종료시키는것은 개발자가 종료시켜야 한다. stopSelf() , stopService()로 종료시킨다.(바인드된 경우는 제외)


onBind()

다른 구성요소가 해당 서비스에 bindService로 바인드 되고자 할 때 (예: RPC를 수행할 때) 호출된다. 이 메소드를 구현할 때 클라이언트가 서비스랑 통신할 수 있는 인터페이스를 제공해야 한다. 이 때 IBinder를 반환하면 된다. 바인딩을 허용하지 않을 때는 null을 반환한다. 


onCreate()

서비스가 처음 생성되어 일회성 절차를 수행할 때 호출된다.


onDestroy()

해당 서비스를 더 이상 사용하지 않고 소멸될 때 호출된다. 쓰레드, 리스너, 수신기 등의 모든 리소스를 정리할 수 있다. 


*Android에서 서비스를 종료시키는 경우는 포그라운드에 있는 액티비티가 요구하는 리소스를 회복해야 하는 경우로 국한된다. 해당 서비스가 포그라운드에 있는 액티비티에 바인딩 되어 있다면 종료될 가능성이 낮다.

*보안을 위해 서비스를 시작하거나 바인드 할 때, 명시적 인텐트로 시작하는것을 권장한다. 서비스에 대한 인텐트 필터는 선언하지 않는다. 어느 서비스를 시작할지 어느정도 모호성이 필요한 경우, 서비스에 대한 인텐트 필터를 제공하고 구성요소 이름을 인텐트에서 제외시킬 수 있지만, 그러려면 해당 인텐트의 패키지를 setPackage()로 설정하여 대상 서비스에 대해 충분히 명확성을 제공한다.