마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

매일 자정에 broadcastReceiver 실행 질문입니다.

0 추천

한때 이슈가 된 사항이죠. 지금도 뾰족한 해법이 나오지 않은거 같은데 혹시나 해서 질문 올려 봅니다.

 

매일 자정에 백그라운드에서 작업을 처리해야 하는 앱을 개발중입니다.

안드로이드8 이후로는 일반 앱에서 ACTION_DATE_CHANGED를 수신 못하기 때문에 Job이든 WorkManager든 AlarmManager를 사용해서 매일 자정에 실행되도록 해야 하는데, 문제가 얘네들은 앱이 죽을때 같이 죽어버린다는거죠. 어떤 앱이든 절대, 무조건 오류가 생기지 않도록 만드는건 사실상 불가능한 일이고, 이 때문에 죽지 않는 service, alarmManager 등 여러 대안이 나왔지만 이런것들도 지난 android update에서 전부 막혀버린걸로 보이네요.

그럼 현 상황에서 매일 자정에 무조건 실행이 보장되는 background service를 만드는건 불가능한 건가요?

 

참고를 위해 덧붙이자면 현재 자정 이벤트 실행 프로세스는 이렇습니다.

1. 앱 설치 시, broadcastReceiver에서 ACTION_PACKAGE_ADDED 이벤트를 수신하고 workManager 실행 

2. workManager에서 매일 자정에 trigger되는 alarmManager 등록

관련 소스

class ReceiverForBootOrDateTimeChanged : BroadcastReceiver() {
    @SuppressLint("ApplySharedPref")
    override fun onReceive(context: Context, intent: Intent) {
        val action = intent.action

        Timber.tag("sdfgdswert").d("$action onReceive()")

        if (Intent.ACTION_PACKAGE_ADDED == action || // 패키지 설치
            Intent.ACTION_PACKAGE_REPLACED == action || // 교체? 앱 업데이트의 경우인듯?
            Intent.ACTION_BOOT_COMPLETED == action || // 부팅
            Intent.ACTION_DATE_CHANGED == action || // 날짜 변경(작동 안함?)
            Intent.ACTION_TIME_CHANGED == action || // 사용자가 직접 시간 변경
            Intent.ACTION_TIMEZONE_CHANGED == action) // 시간대 변경
        { // 위의 이벤트 시 자정에 실행되는 alarm manager 등록 작업 시작

            val worker = OneTimeWorkRequestBuilder<WorkerForBootOrDateTimeChanged>()

            val workManager = WorkManager.getInstance(context)
            workManager.beginUniqueWork(WORK_NAME_FOR_BOOT_OR_DATETIME_CHANGED, ExistingWorkPolicy.REPLACE, worker.build()).enqueue()

            if(BuildConfig.DEBUG){
                CoroutineScope(Dispatchers.Default).launch {
                    RoomDatabaseDebug.getInstance(context).debugLogDao().insert("ReceiverForBootOrDateTimeChanged onReceive() action: $action")
                }
            }
        }
    }
}
class WorkerForBootOrDateTimeChanged(private val context: Context, params: WorkerParameters): Worker(context, params) {
    override fun doWork(): Result {
        setAlarmForNextMidnight(context)

        return Result.success()
    }
}
fun setAlarmForNextMidnight(context: Context) {
    Timber.d(" setAlarmForNextMidnight()")
    val calendarTomorrow = Calendar.getInstance()
    calendarTomorrow[Calendar.HOUR_OF_DAY] = 0
    calendarTomorrow[Calendar.MINUTE] = 0
    calendarTomorrow[Calendar.SECOND] = 0
    calendarTomorrow[Calendar.MILLISECOND] = 0
    calendarTomorrow.add(Calendar.DATE, 1)

    val intentMidnight = Intent(context, BroadcastReceiverForMidnight::class.java)
    val flags = PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
    val pendingIntent = PendingIntent.getBroadcast(context, 875976, intentMidnight, flags)

    val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager

    val alarmClockInfo = AlarmManager.AlarmClockInfo(calendarTomorrow.timeInMillis, pendingIntent)
    alarmManager.setAlarmClock(alarmClockInfo, pendingIntent)
}

 

zent (1,360 포인트) 님이 2022년 8월 8일 질문
zent님이 2022년 8월 8일 수정

답변 달기

· 글에 소스 코드 보기 좋게 넣는 법
· 질문에 대해 추가적인 질문이나 의견이 있으면 답변이 아니라 댓글로 달아주시기 바랍니다.
표시할 이름 (옵션):
개인정보: 당신의 이메일은 이 알림을 보내는데만 사용됩니다.
스팸 차단 검사:
스팸 검사를 다시 받지 않으려면 로그인하거나 혹은 가입 하세요.
...