Android App/Kotlin

4대 컴포넌트-서비스 실행(포어그라운드 서비스)

AppJinny 2022. 12. 2. 23:36

*4대 컴포넌트-서비스 실행(포어그라운드 서비스)

*Foreground Service(포어그라운드 서비스)

-사용자에게 알림을 통해 현재 작업이 진행 중이라는 것을 알려줌

-사용자가 알림을 통해 서비스가 동작하고 있다는 것을 인지하여 가용 자원 부족과 같은 이유로는 종료되지 않음

-서비스를 먼저 생성 후 시스템에 포어그라운드로 사용된다는 것을 알려줘야 함

-실행구조를 기준으로 포어그라운드와 백그라운드 서비스로 분류

-기본적으로 서비스는 모두 백그라운드 서비스(화면에 나타나지 않는 서비스를 뜻함 : 스타티드서비스, 바운드서비스)

-포어그라운드 서비스 3단계

--포어그라운드 서비스 권한 명세

--서비스의 선행

--서비스 안에서 startForeground() 메서드 호출하여 서비스가 포어그라운드로 실행되고 있음을 안드로이드에게 알림

 

 

*포어그라운드 서비스 실행

-build.gradle

-- android{} 에 뷰바인딩 추가

//뷰바인딩
buildFeatures{
    viewBinding true
}

 

-MainActivity.kt

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.core.content.ContextCompat
import com.heeyjinny.foregroundservice.databinding.ActivityMainBinding

//1
//포어그라운드 서비스를 사용하기 위해
//AndroidManifest.xml 포어그라운드 권한 추가

//2
//app - java 패키지명 우클릭 - New - Service - Service
//Foreground.kt 생성

class MainActivity : AppCompatActivity() {

    //뷰바인딩
    val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)

        //3
        //시작버튼 클릭 시 서비스 시작코드 작성
        binding.buttonStart.setOnClickListener {
            //3-1
            //인텐트 생성
            val intent = Intent(this, Foreground::class.java)
            //3-2
            //포어그라운드 서비스 실행 메서드 작성
            //startService()가 아닌
            //ContextCompat.startForegroundService()사용
            ContextCompat.startForegroundService(this, intent)
        }

        //4
        //종료버튼 클릭 시 서비스 종료코드 작성
        binding.buttonStop.setOnClickListener {
            //4-1
            //인텐트 생성하고 종료 메서드 작성하여 인텐트 전달
            val intent = Intent(this, Foreground::class.java)
            stopService(intent)
        }

        //5
        //에뮬레이터 실행 후 확인
        //상단에 아이콘이 떠있고 알림창 생성됨
        //포어그라운드는 사용자에게 현재 서비스가 실행 중임을 항상 알려줘야 함
        //실행한 액티비티를 강제 종료해도 서비스가 실행되기 때문에 알림이 사라지지 않음

    }//onCreate
}//MainActivity

 

-AndroidManifest.xml

--<manifest/>태그에 포어그라운드 서비스 권한 추가

<!-- 포어그라운드 서비스 권한 추가 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

 

-Foreground.kt

import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.Build
import android.os.IBinder
import androidx.core.app.NotificationCompat

class Foreground : Service() {

    //2
    //포어그라운드 서비스를 사용하기 위해서는 상태바에 알림을 띄워야함
    //이 알림이 사용할 채널을 설정할 때 사용하는 상수 정의
    val CHANNEL_ID = "ForegroundChannel"

    override fun onBind(intent: Intent): IBinder {
        //1
        //오류를 막기위해 비어있는 바인더 리턴
        return Binder()
    }//onBind

    //3
    //포어그라운드 서비스에 사용할 알림 실행 전
    //알림채널을 생성하는 메서드 생성
    //모든 알림은 채널 단위로 동작하도록 설계되어 있음
    fun createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val serviceChannel = NotificationChannel(
                CHANNEL_ID,
                "Foreground Service Channel",
                NotificationManager.IMPORTANCE_DEFAULT
            )
            val manager = getSystemService(NotificationManager::class.java)
            manager.createNotificationChannel(serviceChannel)
        }
    }

    //4
    //onStartCommand()메서드 오버라이드
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {

        //4-1
        //앞에서 만들어둔 메서드를 호출해 알림채널 생성
        createNotificationChannel()

        //4-2
        //알림 생성: 알림제목, 알림 아이콘 설정
        val notification: Notification = NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("Foreground Service")
            .setSmallIcon(R.mipmap.ic_launcher_round)
            .build()

        //4-3
        //알림 실행 메서드 사용
        startForeground(1, notification)

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

    //5
    //서비스 실행할 버튼 배치
    //activity_main.xml 에서 버튼 생성

}//Foreground

 

-activity_main.xml 

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

<!--  서비스 시작, 종료 버튼 생성  -->
    <Button
        android:id="@+id/buttonStart"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:text="서비스 시작"
        app:layout_constraintEnd_toStartOf="@+id/buttonStop"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/buttonStop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:text="서비스 종료"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/buttonStart"
        app:layout_constraintTop_toTopOf="parent" />

<!--  액티비티에서 서비스를 호출하기 위해  -->
<!--  MainActivity.kt 작성  -->

</androidx.constraintlayout.widget.ConstraintLayout>

 

-결과

 

 

 


이 포스팅에 작성한 내용은 고돈호, ⌜이것이 안드로이드다⌟, 한빛미디어(주), 2022 에서 발췌하였습니다.