안드로이드 백그라운드 서비스 예제 - andeuloideu baeggeulaundeu seobiseu yeje

백그라운드 서비스 만들기

컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.

IntentService 클래스는 단일 백그라운드 스레드에서 작업을 실행하기 위한 간단한 구조를 제공합니다. 이를 통해 사용자 인터페이스의 반응에 영향을 미치지 않고 장기 실행 작업을 처리할 수 있습니다. 또한, IntentService는 대부분의 사용자 인터페이스 수명 주기 이벤트의 영향을 받지 않으므로 AsyncTask를 종료하는 상황에서 계속 실행됩니다.

IntentService에는 몇 가지 제한사항이 있습니다.

  • 사용자 인터페이스와 직접 상호작용할 수 없습니다. 결과를 UI에 배치하려면 Activity로 보내야 합니다.
  • 작업 요청이 순차적으로 실행됩니다. 작업이 IntentService에서 실행 중일 때 다른 요청을 전송하면, 요청은 첫 번째 작업이 끝날 때까지 대기합니다.
  • IntentService에서 실행되는 작업은 중단할 수 없습니다.

그러나, 대부분의 경우 IntentService는 간단한 백그라운드 작업을 실행하는 데 선호되는 방법입니다.

이 가이드에서는 다음 작업을 실행하는 방법을 보여줍니다.

  • IntentService의 자체 서브클래스를 만듭니다.
  • 필수 콜백 메서드 onHandleIntent()를 만듭니다.
  • 매니페스트 파일에서 IntentService를 정의합니다.

수신 인텐트 처리

앱의 IntentService 구성요소를 만들려면 IntentService를 확장하는 클래스를 정의하고 그 안에 onHandleIntent()를 재정의하는 메서드를 정의합니다. 예:

Kotlin

    class RSSPullService : IntentService(RSSPullService::class.simpleName)

        override fun onHandleIntent(workIntent: Intent) {
            // Gets data from the incoming Intent
            val dataString = workIntent.dataString
            ...
            // Do work here, based on the contents of dataString
            ...
        }
    }
    

자바

    public class RSSPullService extends IntentService {
        @Override
        protected void onHandleIntent(Intent workIntent) {
            // Gets data from the incoming Intent
            String dataString = workIntent.getDataString();
            ...
            // Do work here, based on the contents of dataString
            ...
        }
    }
    

정규 Service 구성요소의 다른 콜백(예: onStartCommand())은 IntentService에서 자동으로 호출합니다. IntentService에서 이러한 콜백을 재정의하면 안 됩니다.

IntentService 만들기에 관한 자세한 내용은 IntentService 클래스 확장을 참조하세요.

매니페스트에서 인텐트 서비스 정의

IntentService는 애플리케이션 매니페스트에도 항목이 필요합니다. 이 항목을 <application> 요소의 하위 요소인 <service> 요소로 제공합니다.

        <application
            android:icon="@drawable/icon"
            android:label="@string/app_name">
            ...
            <!--
                Because android:exported is set to "false",
                the service is only available to this app.
            -->
            <service
                android:name=".RSSPullService"
                android:exported="false"/>
            ...
        </application>
    

android:name 속성은 IntentService의 클래스 이름을 지정합니다.

<service> 요소에는 인텐트 필터가 포함되어 있지 않습니다. 서비스로 작업 요청을 보내는 Activity는 명시적인 Intent를 사용하므로 필터가 필요하지 않습니다. 이것은 또한 동일한 앱 또는 동일한 사용자 ID를 가진 다른 애플리케이션의 구성요소만 서비스에 액세스할 수 있다는 것을 의미합니다.

기본 IntentService 클래스가 있으며 Intent 객체를 사용하여 이 클래스로 작업 요청을 보낼 수 있습니다. 이러한 객체를 구성하고 IntentService에 보내는 절차는 백그라운드 서비스로 작업 요청 보내기에서 설명합니다.

Content and code samples on this page are subject to the licenses described in the Content License. Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.

Last updated 2020-06-20 UTC.

[{ "type": "thumb-down", "id": "missingTheInformationINeed", "label":"필요한 정보가 없음" },{ "type": "thumb-down", "id": "tooComplicatedTooManySteps", "label":"너무 복잡함/단계 수가 너무 많음" },{ "type": "thumb-down", "id": "outOfDate", "label":"오래됨" },{ "type": "thumb-down", "id": "translationIssue", "label":"번역 문제" },{ "type": "thumb-down", "id": "samplesCodeIssue", "label":"샘플/코드 문제" },{ "type": "thumb-down", "id": "otherDown", "label":"기타" }] [{ "type": "thumb-up", "id": "easyToUnderstand", "label":"이해하기 쉬움" },{ "type": "thumb-up", "id": "solvedMyProblem", "label":"문제가 해결됨" },{ "type": "thumb-up", "id": "otherUp", "label":"기타" }]

우찬쓰 개발블로그

안드로이드 백그라운드 서비스 만들기 본문

안드로이드가 오레오, 파이로 넘어가면서 백그라운드 서비스를 다루기가 점점 어려워지고 있다.

사실 어려워진다는 얘기도 백그라운드에서 서비스를 돌리면서도 Notification을 띄우지 않는 기술에 대한 꼼수(?)가 어려워 지고 있는거지 Notification이 뜨든 말든 상관없는 초보자들은 더 혼동이 오기 마련이다.

그래서 안드로이드 초보자의 기준에서, 안드로이드의 백그라운드 서비스를 공식적인 방법으로 띄우는 방법에 대해 알아보자.

여기서 용어를 정의하고 넘어가야 하는데, 앱이 죽든 말든 백그라운드에서 서비스를 죽지않게 하고 싶다면 이것을 포어그라운드 서비스 라고 한다.

따라서 이하 포어그라운드 서비스 라고 부르겠다.

먼저 서비스를 만들어야 하는데 생각보다 간단하다.

서비스를 상속받은 예제 서비스를 만들자

class TestService : Service() {

    override fun onCreate() {
        super.onCreate()
        
        // 오레오 부터는 notification channel을 설정해 주어야 함
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val name = "Test Notification"
            val importance = NotificationManager.IMPORTANCE_DEFAULT
            val notificationChannel = NotificationChannel("YOUR_CHANNEL_ID", name, importance)

            val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(notificationChannel)
        }
        
        // TODO : 아래 주석 인텐트는 해당 Notification을 눌렀을때 어떤 엑티비티를 띄울 것인지 정의.
        // val notificationIntent = Intent(this, TestActivity::class.java)
        // val pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0)
        val builder = NotificationCompat.Builder(this, "YOUR_CHANNEL_ID")
            .setSmallIcon(R.drawable.test_icon)
            .setContentText("test")
            //.setContentIntent(pendingIntent)
        startForeground(1, builder.build())
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    	// TODO : 서비스 처음 시작시 할 동작 정의.
        return START_REDELIVER_INTENT
    }

    override fun onDestroy() {
	// TODO : 서비스 종료시 할 것들
        super.onDestroy()
    }
}

그리고 Activity에서 

val intent = Intent(context, TestService::class.java)
startService(intent)

를 호출하면 끝이다.

생각보다 간단한데, 이렇게 간단한 예제 하나가 정리되어있는게 없다는게 참 아쉽다.

아마 다들 알겠지만 Google 정책이 바뀌면서 포어그라운드 서비스를 돌리기 위해서는 Notification이 항상 띄워져 있어야 한다.

그렇지 않으면 서비스가 돌지 않는다.

그리고 서비스를 더이상 돌리고 싶지 않다면

val intent = Intent(context, TestService::class.java)
stopService(intent)

를 호출해 주는것도 잊지 않도록 하자.

더 나아가서, 포어그라운드 서비스와 엑티비티간 통신을 구현해 보자.

서비스와 엑티비티간 통신에는 LocalBroadcastManager를 사용한다.

먼저 서비스 부분에서 엑티비티로 보내기 위한 부분을 세팅해보자.

val localBroadcastManager = LocalBroadcastManager.getInstance(this)
val intent = Intent("intent_action")
intent.putExtra("test", "testString")
localBroadcastManager.sendBroadcast(intent)

그 다음 엑티비티에서도 값을 전달받기 위해 다음과 같이 세팅한다.

val messageReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val test = intent.getStringExtra("test")
        println(test)
    }
}

LocalBroadcastManager.getInstance(this).registerReceiver(messageReceiver, IntentFilter("intent_action"))

매우 잘 작동하는 것을 확인할 수 있다.

엑티비티에서 서비스로 값을 전달할 때도 이와 같이 작업하면 된다.