Android 서비스 컴포넌트

timothy jeong·2021년 11월 14일
0

Android with Kotlin

목록 보기
42/69

서비스란?

서비스 컴포넌트는 백그라운드에서 오래 실행되는 작업을 수행하는 것이 목적인 컴포넌트이다. 따로 사용자 인터페이스를 제공하지 않는다. 사용자가 다른 어플리케이션으로 전환하더라고 백그라운드에서 계속 실행된다.

또한 컴포넌트를 서비스에 바인딩하여 서비스와 상호작용할 수 있으며, 프로세스 간 통신(IPC)도 수행할 수 있다. 예를 들어 한 서비스는 네트워크 트랜잭션을 처리하고, 음악을 재생하고 파일 I/O를 수행하거나 콘텐츠 제공자와 상호작용할 수 있으며 이 모든 것을 백그라운드에서 수행할 수 있다.

서비스와 스레드

메인 스레드 이외에 작업을 해야하는 경우에는 반드시 서비스를 써야만하는 것은 아니다. 스레드를 하나 더 만들어서 사용하거나(AsyncTask, HandlerThread), 코루틴을 이용하는 것도 방법이 될 수 있다. 물론 서비스 내부에서 스레드를 또 나누는 것도 가능하다.

서비스의 종류

포그라운드

포그라운드 서비스는 사용자에게 잘 보이는 작업을 수행한다. 예를 들어 오디오 앱이라면 오디오 트랙을 재생할 때 포그라운드 서비스를 사용한다. 포그라운드 서비스는 알림을 표시해야 합다. 포그라운드 서비스는 사용자가 앱과 상호작용하지 않을 때도 계속 실행된다.

백그라운드

백그라운드 서비스는 사용자에게 직접 보이지 않는 작업을 수행한다. 예컨대 어느 앱이 저장소를 압축하는 데 서비스를 사용했다면 보통 백그라운드 서비스를 이용한 것이다.

바인드

안드로이드 컴포넌트가 bindService()를 호출하여 해당 서비스에 바인딩되면 서비스가 바인딩된다.

바인딩된 서비스는 클라이언트-서버 인터페이스를 제공하여 컴포넌트가 서비스와 상호작용하게 하며, 결과를 받을 수도 있고 이와 같은 작업을 여러 프로세스에 걸쳐 프로세스 간 통신(IPC)으로 수행할 수도 있다. 바인딩된 서비스는 또 다른 컴포넌트가가 이에 바인딩되어 있는 경우에만 실행된다. 여러 컴포넌트가 서비스에 한꺼번에 바인딩될 수 있지만, 이 모든 것에서 바인딩이 해제되면 해당 서비스는 소멸된다.

서비스 생성과 실행

서비스 컴포넌트는 Service 클래스를 상속받아서 작성한다. 서비스에는 다양한 생명주기 함수를 재정의 할 수 있지만, onBind() 는 필수이다.

class MyService: Service() {
    override fun onBind(intent: Intent): IBinder? {
        return null
    }
}

서비스도 컴포넌트 이므로 메니페스트에 등록해야한다.

        <service android:name=".MyService"
            android:enabled="true"
            android:exported="true"/>

서비스를 실행하려면 시스템에 인텐트를 전달해야하는데, 이때 사용하는 함수는 startService() 와 bindService() 2가지이다.

startService() 함수로 실행

해당 서비스를 인텐트에 담아서 매개변수로 전달해야 한다.

val intent = Intent(this, MyService::class.java)
startService(intent)

// 암시적 인텐트 
val intent = Intent("ACTION_OUTER_SERVICE")
intent.setPackage("com.exmple.test_outter")
startService(intent)

stopService(intent)

암시적으로 실행하는 경우, setPackage() 를 해줘야하는데 외부 앱이 백그라운드 상태라면 서비스를 실행할 수 없다. 그리고 서비스를 종료하려면 stopService() 함수로 인텐트를 전달해야 한다.

bindService() 함수로 실행

이 함수로 서비스를 실행하려면 먼저 ServiceConnection 인터페이스를 구현한 객체를 준비해야한다. 이 인터페이스에는 추상함수 onServiceConnected(), onServiceDisconnected() 2개가 정의되어 있다. 각각 이 함수로 서비스를 구동할때, 이 함수로 서비스를 종료할때 자동으로 호출된다.

이렇게 구현한 객체를 bindService() 함수로 인텐트를 시스템에 전달해 서비스를 실행한다. 만약 bindService()로 실행할 서비스가 외부 앱의 것이라면 setPackage() 함수로 패키지명을 명시해야한다.

    val connection: ServiceConnection = object: ServiceConnection {
        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {}
        override fun onServiceDisconnected(name: ComponentName?) {}
    }
    
val intent = Intent(this, MyService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE)

unbindService(connection)

bindService() 함수의 매개변수는 3개이다. 첫번째는 인텐트 객체, 두번째는 ServiceConnection 을 구현한 객체이다. 세 번째 매개변수는 Int 타입의 flags 인데 이 값은 대부분 Context.BIND_AUTO_CREATE 로 지정한다. 이는 서비스가 실행 상태가 아니더라도 객체를 생성해서 실행하라는 의미이다. 만약 Context.BIND_AUTO_CREATE 를 지정하지 않으면 bindService() 함수로 인텐트를 전달해도 서비스가 실행 상태가 아니면 동작하지 않는다. 이렇게 실행한 서비스는 unbindService()로 종료한다.

서비스 생명주기

어떤 함수로 서비스를 실행하느냐에 따라 생명주기가 나뉜다.

startService() -> onCreate() -> onStartCommand() -> 서비스 실행 -> onDestroey() -> 서비스 종료

bindService() ->onCreate() -> onBind() -> 컴포넌트를 서비스에 바인딩 -> onUnbind() -> onDestroy() -> 서비스 종료

profile
개발자

0개의 댓글