[안드로이드] Service
1. Service란?
Service는 안드로이드 Application을 구성하는 4대 컴포넌트 중 하나이다. Activity처럼 사용자와 상호 작용을 하는 컴포넌트는 아니다. 때문에 UI가 존재하지 않으며 Background에서 동작하는 컴포넌트이다.
Service가 실행되고 있는 상태라면 안드로이드 OS에서는 해당 Process를 왠만하면 죽이지 않도록 방지하고 관리하게 된다. 그렇기 때문에 메모리 부족이나, 특별한 경우를 제외하고는 Background 동작을 수행하도록 설계되었다.
2. Service는 왜 필요할까?
'Android Application을 구성하기 위해서 Service는 왜 필요할까?'라고 생각을 할 수 있다. 그 이유는 Activity 즉, 사용자가 보고 있는 화면이 종료된 상태에서도 동작하기 위해서 만들어졌고, 개발자는 구현을 해야 한다.
예를 들어서 Mp3 플레이어 같은 기능을 활용하는 경우가 될 수 있다. Mp3 플레이어는 화면이 종료된 상태에서도 계속 노래를 재생해야 하기 때문에 Background에서도 동작하도록 만들어야 한다. 따라서 Service를 사용해 구현하면 된다.
- 파일 다운로드 같은 경우에도 사용할 수 있다.
- 애플리케이션이 실행 중이지 않을 때도 작업해야 하는 경우에도 사용할 수 있다.(애플리케이션이 실행 중일 때만 작업해야 하는 경우 스레드 사용을 권장한다.)
주의
Service가 Background에서 동작을 수행하는 컴포넌트라고 해서 Main Thread에서 실행되는 것이라고 생각하지 않을 수도 있다. 명심해야 할 점은 Android 4대 컴포넌트들은 모두 Main Thread에서 실행된다.
따라서 CPU 자원을 많이 소모하거나 네트워크 통신과 같은 시간이 오래 걸리는 작업은 별도의 Thread를 만들어서 처리해야 한다. 이 부분은 아래에서 ANR과 함께 설명하겠다.
3. Service 사용 방법
2가지 방법이 있으면 startService()
와 bindService()
이다.
- startService() - 시작 타입의 서비스
- 서비스를 상속받는 클래스를 작성하며, 정적 리시버와 유사하게 매니페스트 파일에 등록한다.
- 한 번 시작되면 백그라운드에서 무한정 실행된다.
- 작업을 완료하면 서비스가 종료된다.
- 간단한 작업들만 수행한다.
- 호출한 곳에 결과값을 반환하지 않고 계속해서 서비스한다.(음악 재생, 파일 다운로드 등)
- 하나의 프로세스 안에서 동작하며, 패키지내 컴포넌트들과 유기적으로 통신하는 역할을 한다.
- 생명 주기 : onCreate() -> onStartCommand() -> 실행 -> onDestroy() -> stopService()
- bindService() - 연결 타입의 서비스
- 클라이언트 - 서버와 같이 동작하며 호출자(액티비티)에서 서비스에게 어떤 것을 요청하고 서비스는 요청을 처리한 후 결과값을 반환한다. (서비스가 서버의 역할을 수행.)
- 액티비티가 사라지면 서비스도 자동적으로 destroy되면서 없어진다.
- 하나의 서비스가 다수의 액티비티와 연결될 수 있다.
- 프로세스 내에서 다른 컴포넌트들과 서로 유기적으로 통신을 하며 또한, 어플 내의 기능을 외부에 제공하는 경우에 많이 사용된다. 즉, 다른 프로세스들 간에서도 Data 공유 및 통신이 유기적으로 가능하다.
- 생명 주기 : onCreate() -> onBind() -> 실행 -> onUnbind() -> onDestory() -> stopService()
- intentService
- 내부적으로 handlerThread가 동작하는 서비스
- 루퍼가 message Queue에 들어온 요청에 대해 순차적으로 처리한다.
- Queue가 비게 되면 자동으로 서비스가 종료된다.
- 동시에 처리하는게 아니므로 성능은 조금 떨어지지만 순차적 실행이 보장된다.
4. Service 사용시 주의사항.
Android는 Linux 기반의 프로그램이다. 프레임워크 단에는 Linux로 구현되어 있다. 메모리 관리 또한 Linux 정책을 따르며 Linux Kernel에 의해서 관리된다.
결국 여러 프로세스들을 커널에서 관리한다고 짐작할 수 있다.
또한 하나의 프로세스 안에는 애플리케이션, 안드로이드 4대 컴포넌트, 스레드 등을 구성하고 있다. 즉, 4대 컴포넌트의 운명 또한 리눅스 커널에 달려있다는 걸 의미한다.
만약, 메모리 부족이나 과부하 등과 같은 현상이 발생했을 때 리눅스 커널이 프로세스를 강제로 종료시킬 수 있다.
여기서 주의해야 할 점이 있다. 바로 모든 컴포넌트들이 Main Thread 안에서 실행된다는 점이다. 안드로이드에서 Main Thread는 UI 작업을 처리하는 Thread이다. 따라서 Main Thread에서는 네트워크 작업이나 시간이 오래 걸리는 작업을 하게 되면 앱의 반응성이 낮아질 수 있다. 사용자의 불편함을 방지하고나 시스템이 ANR
상태로 전환시킬 수 있다.
Service 역시 Main Thread에서 동작하기 때문에 시간이 오래 걸리는 작업을 할 경우에는 별도의 작업 Thread를 만들어서 동작을 처리해야 한다. 그리고 작업 결과를 UI Thread에 반영하기 위해서 쓰레드 간 통신 방법을 이용해 반영해야 한다.
쓰레드간 통신 방법은 다음의 글을 참고하면 보면 될 것 같다.
쓰레드간 통신 방법
추가적인 내용들은 빠른 시일 내에 공부해서 포스팅할 예정이다.