[안드로이드스튜디오_문화][ForegroundService]

기말 지하기포·2023년 11월 29일
0

#Service Android Developer 공식 문서
=> https://developer.android.com/guide/components/services?hl=ko

Background Service

-Background Service는 사용자에게 보이지 않는 작업을 수행한다.

-Jetpack의 WorkManager가 나와서 굳이 Background Service를 사용 할 필요성이 없어서 백그라운드에서 작업한는 것은 추후에 WorkManager를 통해서 다루겠음.

Foreground Service 생명주기

onCreate()

-서비스가 처음 생성 될 때 호출된다. 이 메서드에서는 서비스의 초기 설정을 진행 하는 생명 주기 단계이다. 만약 서비스가 이미 실행중이라면 onCreate()는 호출되지 않는다.

-그러나 굳이 Service 생명주기의 onCreate()에서 하지 않아도 된다. 다른 클래스에서 서비스에 대한 초기 설정을 진행해줘도 괜찮다.

onStartCommand(Intent , int , int)

-서비스가 시작 될 때마다 호출되는 메서드로서 startService()가 호출되면 해당 생명주기가 시작된다.

-해당 생명주기에서는 서비스가 수행할 작업을 정의하며 , 이 생명주기 내부에서 startForeground()를 호출하여 사용자에게 서비스가 실행중인 알림을 표시해야 한다.

onBind(Intent)

-서비스가 클라이언트에 의해 바인드 되어야 하는 경우 호출하는데 , Foreground Service는 일반적으로 바인딩을 위해 사용되지 않으므로 'null'을 반환하는 것이 일반적이다.

onDestroy()

-서비스가 더 이상 필요하지 않아서 종료 될 때 호출된다. 이 생명주기에서는 서비스가 자체적으로 stopSelf()를 호출하거나 다른 컴포넌트에서 stopService()를 호출하여 서비스를 종료할 수 있다. 또한 서비스 종료 할 때 필요한 작업들을 수행 할 수 있다.

  • 생명주기가 적용된 예시 코드 (1)
class RunningService : Service() {
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        when(intent?.action) {
            Actions.START.toString() -> start()
            Actions.STOP.toString() -> stopSelf()
        }

        return super.onStartCommand(intent, flags, startId)
    }

    override fun onBind(intent: Intent?): IBinder? {
        return null
	>return null을 한 이유는 서비스가 바인드를 통해서 클라이언트와 상호작용을 하지 않을 것이며,
	>오직 startService(Intent)를 통해 시작되어 백그라운드에서 독립적으로 작업을 수행하는 
    서비스임을 나타내는 것이야.
	>클라이언트가 서비스와 직접적으로 통신하여 서비스의 메서드를 호출할 필요가 없을 때 이 방식을 
    사용한다.

	>서비스로 수행 할 수 있는 작업은 하나의 활성 인스턴스와 여러 구성 요소를 해당 단일 인스턴스에 
    연결하고 해당 서비스와 통신하고 수신하기 위한 통신을 위한 스트림을 수행 하는 것이다
    }


    private fun start() {
        val notification = NotificationCompat.Builder(this , "running_channel")
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setContentTitle("Run is active")
            .setContentText("Elapsed time : 00 : 50")
            .build()


        // startForeground()는 ID와 Notification이 필요하다.
        startForeground(1, notification)
    }

    enum class Actions {
        START , STOP
    }
}

Foreground Service

-Foreground Service는 사용자에게 보이는 몇몇 작업을 수행한다. 또한 Foreground Service는 알림을 표시해야 하며 , 사용자가 앱과 상호작용하지 않을 때도 계속 실행되는 특징이 있다.

AndroidManifest.xml 설정

-Foreground Service를 사용하기 위해서는 AndroidManifest.xml 파일에 Service를 상속받은 클래스를 [service] 태그 내부에 넣어줘야 한다. 이렇게 되면 Android System에서 Service를 사용하겠다는 것을 알려줌으로서 우리가 해당 Service를 사용 할 수 있다.

-우선 Foreground Service를 사용한다는 것은 앱에서 실행되는 알림을 받겠다는 것이므로 알림권한 요청을 허용해주는 코드를 작성해줘야 한다. 따라서 AndroidManifest.xml 파일에 아래와 같은 코드를 추가해줘야 한다.

<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
  • 사용자에게 알림을 게시 할 수 있도록 허용해주는 코드로서 API33 이상부터 사용 할 수 있다.
  • 알림을 게시할 수 있도록 허용 하면 사용자는 알림을 받을 수 있고 허용하지 않으면 앱은 사용자에게 알림을 게시 할 수 없다.
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
  • 포그라운드 서비스를 사용 할 때 선언해줘야 하는 코드로서 사용자에게 지속적으로
    정보를 제공해야 하는 작업에 사용된다. 이로서 백그라운드 제한 없이 장시간 실행되는 서비스를 유지 할 수 있다.
<service android:name=".RunningService" />
  • Application 태그 내부에 service 태그에 Service()를 상속받은 클래스를 넣어준다. 이로서 안드로이드 시스템은 해당 서비스의 존재를 알리고 필요한 해당 서비스가 실행 될 수 있도록 허용한다.

onCreate

-굳이 Service를 상속받은 클래스에서 서비스 초기 설정을 하지 않고 다른 클래스에서 서비스 초기 설정을 진행해줘도 된다. 아래는 예시코드이다.

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
	val channel = NotificationChannel(
		"running_channel",
		"Running Notifications",
		NotificationManager.IMPORTANCE_HIGH
	)
	val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(channel)
}
  • 포그라운드 서비스에서 알림을 보내지건에 알림 채널을 생성해야 한다. 알림 채널을 만들때에는 id와 중요도를 설정해주면된다. NotificationChannel(id , name , 중요도)를 설정한 후 에 notificationManager.createNotificationChannel()의 parameter에 생성한 channel을 넣어주면 된다.
  • 또한 여기서 만든 채널의 id를 Service를 시작하는 코드인 NotificationCompat.Builder(context , channelId)의 channelId에 넣어주면된다.

onStartCommand

-onStartCommand 생명주기에서 진짜 서비스가 실행되는데 이때 어떤 서비스를 실행 할 지 어떡해 알 수 있을 까?

Button(onClick = {
	Intent(applicationContext , RunningService::class.java).also {
		it.action = RunningService.Actions.START.toString()
		startService(it)
	}
}) {
	Text("Start run")
}
  • 위 코드에서 RunningService라는 서비스를 시작하기 위한 인텐트를 만들고 startService를 통해서 서비스를 시작한다. startService()를 실행하였기 때문에 RunningService가 시작되고
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        when(intent?.action) {
            Actions.START.toString() -> start()
            Actions.STOP.toString() -> stopSelf()
        }

        return super.onStartCommand(intent, flags, startId)
    }

-위 코드에서 Actions.START.toStrint()을 통해서 start() 함수가 실행되고

private fun start() {
	val notification = NotificationCompat.Builder(this , "running_channel")
		.setSmallIcon(R.drawable.ic_launcher_foreground)
		.setContentTitle("포그라운드 서비스 시작")
		.setContentText("자고 싶다...")
		.build()

	> startForeground()는 ID와 Notification이 필요하다.
	startForeground(1, notification)
    }

-위 코드가 실행되면서 사용자에게 알림이 가게된다.

onDestory

Button(onClick = {
	Intent(applicationContext , RunningService::class.java).also {
		it.action = RunningService.Actions.STOP.toString()
		startService(it)
	}
}) {
	Text("Stop run")
}
  • 위 코드 또한 RunningService의 Actions.Stop.toString을 실행시켜서
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        when(intent?.action) {
            Actions.START.toString() -> start()
            Actions.STOP.toString() -> stopSelf()
        }

        return super.onStartCommand(intent, flags, startId)
    }
  • 위 코드의 stopSelf()를 호출해서 Service를 종료시키면 된다.

#정리
-AndroidManifest.xml : [Service 선언] , [권한 설정]
-onCreate 또는 다른 클래스에서 서비스 초기 설정
-onStartCommand에서 서비스 액션 코드 지정

-

profile
포기하지 말기

0개의 댓글