[Android, Kotlin] Broadcast Receiver에서의 비동기 백그라운드 작업
Android

[Android, Kotlin] Broadcast Receiver에서의 비동기 백그라운드 작업

Broadcast Receiver의 경우, onReceive() 함수가 실행 중일 때 시스템에서는 해당 프로세스를 포그라운드 프로세스로 간주하여 심각한 메모리 부족이 아닌 이상 프로세스를 종료시키지 않고 수행한다.

onReceive() 함수의 코드가 모두 실행된 뒤 반환을 마치고 나면 비활성 상태로 간주되어 프로세스의 우선순위가 낮아지게 된다.

 

이는 리소스가 부족할 경우 해당 Broadcast Receiver 프로세스가 onReceive 함수가 완료되기 전에 강제 종료 될 수 있음을 의미한다.

 

간단한 ACTION_POWER_CONNECTED와 같은 Action 경우에는 짧은 시간 내에 onReceive 함수의 수행을 완료하므로 영향이 없으나, onReceive 함수가 오랜 시간에 걸친 백그라운드 작업을 다른 스레드에서 수행하게 된다면 수행 완료 여부에 관계없이 onReceive 함수는 값을 반환하게 되고 리소스의 상황에 따라 백그라운드 작업이 완료되기 전에 프로세스가 종료 될 수도 있다.

 

해당 영향에 대해 안드로이드 공식 문서에서는 다음과 같이 말한다.

 

 

요약 - 위와 같은 이유로 Broadcast Receiver에서는 장기간 실행되는 백그라운드 스레드를 수행하면 안된다. 이를 피하려면,

1. goAsync()를 사용하여 Broadcast Receiver가 작업을 완료하는 데에 더 많은 시간이 필요하다는 플래그를 지정할 수 있도록 하거나 2. JobScheduler를 사용한 JobService의 예약을 통해 시스템이 프로세스가 계속해서 작업을 수행함을 알려야한다.

 

본 글에서는 1. goAsync() 사용을 통한 Broadcast Receiver의 백그라운드 작업 수행 방식을 설명한다.

 

 

 

* goAsync() 사용을 통한 Broadcast Receiver 백그라운드 작업 수행

 

goAsync()를 onReceive() 함수에서 사용하여 메인 스레드가 아닌 백그라운드 스레드에서 비동기적으로 작업을 수행하게 한다.

그러나 Broadcast Receiver의 경우, ANR(앱이 응답하지 않음) 에러를 띄우기 전까지 최대 10초의 실행 제한을 둔다.

기본적으로 Broadcast Receiver는 메인 스레드에서 작업이 수행되므로 약 5초의 실행 제한의 제약이 걸린다.

goAsync()를 사용할 때, 백그라운드 스레드에서 비동기 작업을 수행하기 때문에 5초의 실행 제한을 10초로 늘릴 수 있으나 10초보다 더 오래걸리는 작업의 경우에는 goAsync가 아닌 JobScheduler 방식을 사용해야한다.

 

또한, goAsync()의 경우에는 해당 비동기 작업이 완료 될 때까지 다른 broadcast를 차단하므로 broadcast에 대한 응답이 느려질 수 있음에 유의해야 한다.

 

private const val TAG = "MyBroadcastReceiver"

class MyBroadcastReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        val pendingResult: PendingResult = goAsync()
        val asyncTask = Task(pendingResult, intent)
        asyncTask.execute()
    }

    private class Task(
            private val pendingResult: PendingResult,
            private val intent: Intent
    ) : AsyncTask<String, Int, String>() {

        override fun doInBackground(vararg params: String?): String {
            val sb = StringBuilder()
            sb.append("Action: ${intent.action}\n")
            sb.append("URI: ${intent.toUri(Intent.URI_INTENT_SCHEME)}\n")
            return toString().also { log ->
                Log.d(TAG, log)
            }
        }

        override fun onPostExecute(result: String?) {
            super.onPostExecute(result)
            // Must call finish() so the BroadcastReceiver can be recycled.
            pendingResult.finish()
        }
    }
}

 

onReceive() 함수에서 goAsync를 통해 pendingResult를 반환한다. 이는 pendingResult.finish()가 호출되기 전까지는 작업이 실행 중임을 알린다.

AsyncTask 추상 클래스를 상속받은 Task 클래스에서 doInBackground 메소드를 오버라이딩 하여 해당 함수에서 백그라운드 스레드로 작업을 수행한다.

onPostExecute 메소드에서 pendingResult.finish()를 통해 작업이 완료되었음을 알린다.

 

 

 

추후 알아볼 것 : JobScheduler에 대해서 / JobScheduler를 통한 Broadcast Receiver의 장시간 작업 수행

 

출처 : https://developer.android.com/guide/components/broadcasts 

 

브로드캐스트 개요  |  Android 개발자  |  Android Developers

브로드캐스트 개요 Android 앱은 Android 시스템 및 기타 Android 앱에서 게시-구독 디자인 패턴과 유사한 브로드캐스트 메시지를 받거나 보낼 수 있습니다. 관심 있는 이벤트가 발생할 때 이러한 브로

developer.android.com

 

https://roomedia.tistory.com/entry/Broadcast-Receiver-%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%B0%B1%EA%B7%B8%EB%9D%BC%EC%9A%B4%EB%93%9C-%EC%9E%91%EC%97%85-doAsync-JobScheduler

 

#Broadcast Receiver 비동기 백그라운드 작업 #doAsync #JobScheduler

Broadcast Receiver가 프로세스 상태에 미치는 영향 BroadcastReceiver가 onReceive() 메서드를 코드를 실행 중일 때, 해당 수신자는 포그라운드 프로세스로 간주됩니다. 메모리가 부족하지 않은 이상 시스템

roomedia.tistory.com