코틀린 안드로이드 앱개발 강좌, 서비스 이해하기

안드로이드 앱 개발에서 서비스(Service)는 애플리케이션의 UI와 독립적으로 백그라운드에서 작업을 수행할 수 있는 구성 요소입니다. 사용자가 애플리케이션과 상호작용하지 않더라도 서비스를 통해 다양한 작업을 계속 수행할 수 있습니다. 이번 강좌에서는 서비스의 개념, 종류, 생명주기 및 코틀린을 사용한 서비스 구현 방법에 대해 자세히 알아보도록 하겠습니다.

1. 서비스란?

서비스는 안드로이드에서 백그라운드 작업을 처리하는 컴포넌트로, 사용자 인터페이스(UI)와는 독립적으로 작동합니다. 예를 들어, 음악 재생, 파일 다운로드, 또는 데이터 처리와 같은 작업을 사용자 인터페이스와 상관없이 계속 실행할 수 있습니다.

서비스는 애플리케이션의 기능 중 하나이며, 주로 다음과 같은 용도로 사용됩니다:

  • 재생 중인 음악 스트리밍
  • 비디오 스트리밍
  • 파일 다운로드 및 업로드
  • 데이터 동기화 작업

2. 서비스의 종류

안드로이드 서비스는 크게 두 가지로 분류할 수 있습니다:

2.1. 시작 서비스 (Started Service)

시작 서비스는 startService() 메소드를 호출하여 시작할 수 있습니다. 일단 시작되면, 서비스는 독립적으로 실행되고, 사용자가 종료할 때까지 지속됩니다. 사용자는 필요에 따라 stopSelf() 또는 stopService() 메소드를 통해 서비스를 종료할 수 있습니다.

class MyStartedService : Service() {
        override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
            // 작업 수행
            return START_STICKY
        }

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

        override fun onDestroy() {
            super.onDestroy()
        }
    }

2.2. 바인드 서비스 (Bound Service)

바인드 서비스는 다른 컴포넌트(예: Activity)와 연결되어 데이터 및 메소드를 공유하는 서비스입니다. bindService() 메소드를 통해 연결할 수 있으며, 연결이 끊어지면 서비스가 종료될 수 있습니다.

class MyBoundService : Service() {
        private val binder = MyBinder()

        inner class MyBinder : Binder() {
            fun getService(): MyBoundService = this@MyBoundService
        }

        override fun onBind(intent: Intent?): IBinder {
            return binder
        }
    }

3. 서비스의 생명주기

서비스의 생명주기는 Activity와는 약간 다릅니다. 서비스는 다음과 같은 상태를 가집니다:

  • Started: 서비스가 시작되었을 때의 상태
  • Running: 서비스가 백그라운드에서 작업을 수행하는 상태
  • Stopped: 서비스가 종료된 상태

서비스 생명주기 메소드는 다음과 같습니다:

  • onCreate(): 서비스가 생성될 때 호출됩니다.
  • onStartCommand(): 서비스가 시작될 때 호출됩니다.
  • onBind(): 다른 컴포넌트가 서비스에 바인드될 때 호출됩니다.
  • onUnbind(): 서비스와의 바인딩이 해제될 때 호출됩니다.
  • onDestroy(): 서비스가 종료될 때 호출됩니다.

3.1. 서비스 생명주기 예제

class MyService : Service() {
        override fun onCreate() {
            super.onCreate()
            Log.d("MyService", "Service Created")
        }

        override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
            Log.d("MyService", "Service Started")
            return START_STICKY
        }

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

        override fun onDestroy() {
            Log.d("MyService", "Service Destroyed")
            super.onDestroy()
        }
    }

4. 서비스 구현하기

이제 코틀린을 사용하여 간단한 시작 서비스를 구현해보겠습니다. 이 서비스는 백그라운드에서 10초 동안 작업을 수행한 후 종료됩니다.

4.1. 프로젝트 설정

  1. 안드로이드 스튜디오를 열고 새로운 프로젝트를 생성합니다.
  2. Minimum API Level을 선택합니다 (예: API 21 – Lollipop).
  3. Empty Activity 템플릿을 선택한 후 프로젝트 이름을 설정합니다.

4.2. 서비스 클래스 생성

MyService라는 이름의 서비스를 생성합니다.

class MyService : Service() {
        override fun onCreate() {
            super.onCreate()
            Log.d("MyService", "Service Created")
        }

        override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
            Log.d("MyService", "Service Started")
            // 백그라운드 작업 수행
            Thread {
                // 10초 대기 후 서비스 종료
                Thread.sleep(10000)
                stopSelf()
            }.start()
            return START_STICKY
        }

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

        override fun onDestroy() {
            Log.d("MyService", "Service Destroyed")
            super.onDestroy()
        }
    }

4.3. AndroidManifest.xml에 서비스 등록

<service android:name=".MyService"></service>

4.4. 서비스 시작하기

MainActivity에서 서비스를 시작하는 코드를 추가합니다.

class MainActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)

            val startServiceButton = findViewById

4.5. 앱 실행 및 테스트

앱을 실행한 후 “서비스 시작” 버튼을 클릭하면 로그캣에서 “Service Created”, “Service Started”, “Service Destroyed” 메시지를 확인할 수 있습니다.

5. 서비스와 스레드

서비스의 onStartCommand() 메소드에서 긴 작업을 수행하면 ANR(Application Not Responding) 오류가 발생할 수 있습니다. 따라서 백그라운드에서 실행할 작업은 Thread, AsyncTask, 또는 Coroutine에 위임하는 것이 좋습니다.

5.1. 코틀린 Coroutines 사용하기

코틀린의 Coroutines를 사용하면 간편하게 비동기 작업을 처리할 수 있습니다. 다음은 Coroutine을 이용한 서비스 구현 예제입니다.

class MyCoroutineService : Service() {
        private val job = Job()
        private val coroutineScope = CoroutineScope(Dispatchers.Main + job)

        override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
            coroutineScope.launch {
                // 10초 대기
                delay(10000)
                Log.d("MyCoroutineService", "Service Completed")
                stopSelf()
            }
            return START_STICKY
        }

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

        override fun onDestroy() {
            job.cancel()
            super.onDestroy()
        }
    }

6. 결론

이번 강좌에서는 코틀린을 활용하여 안드로이드 앱 개발에서 서비스의 개념, 종류, 생명주기 및 구현 방법에 대해 알아보았습니다. 서비스는 백그라운드에서 작업을 수행하는데 유용하며, 안드로이드 애플리케이션의 핵심 요소 중 하나입니다.

다음 강좌에서는 BroadcastReceiver와 IntentService에 대해 다룰 예정이니 기대해 주세요!

© 2023 안드로이드 개발 강좌. 모든 권리 보유.