I have a requirement to perform a task at exactly every 5 minutes. I have considered multiple options and have attempted to implement this using the AlarmManager
class to trigger the task. However I cannot get the alarm to trigger when the application has been killed.
The alarm seems to work flawlessly when the app is open, or running in the background, but as soon as I exit the app, it seems to completely stop.
My implementation is to use the setExactAndAllowWhileIdle()
function and to handle the repeating of this myself. The initial alarm is triggered after 5 seconds, then every 5 minutes after this.
I have tested this with 5 and 10 minute increments, but again this never runs when the app is closed.
Please take a look at my implementation:
My Activity.kt:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_landing)
initAlarm()
}
private fun initAlarm() {
val alarm = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(this, AlarmReceiver::class.java).apply { action = "MY_ALARM" }
val sender = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val ALARM_DELAY_IN_SECOND = 5
val alarmTimeAtUTC = System.currentTimeMillis() + ALARM_DELAY_IN_SECOND * 1_000
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Log.(TAG, "initAlarm() 23+ - $alarmTimeAtUTC")
alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmTimeAtUTC, sender)
} else {
alarm.setExact(AlarmManager.RTC_WAKEUP, alarmTimeAtUTC, sender)
}
}
AlarmReceiver.kt:
class AlarmReceiver : BroadcastReceiver() {
companion object {
private val TAG = AlarmReceiver::class.java.simpleName
}
override fun onReceive(context: Context?, intent: Intent?) {
Log.d(TAG, "onReceive()")
if (intent?.action == "MY_ALARM") {
Log.d(TAG, "onReceive() - starting service")
context?.startService(Intent(context, MyService::class.java))
initAlarm(context)
}
}
private fun initAlarm(context: Context?) {
val alarm = context?.applicationContext?.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(context, AlarmReceiver::class.java).apply { action = "MY_ALARM" }
val sender = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val ALARM_DELAY_IN_SECOND = 600
val alarmTimeAtUTC = System.currentTimeMillis() + ALARM_DELAY_IN_SECOND * 1_000
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Log.d(TAG, "initAlarm() 23+ - $alarmTimeAtUTC")
alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmTimeAtUTC, sender)
} else {
alarm.setExact(AlarmManager.RTC_WAKEUP, alarmTimeAtUTC, sender)
}
}
}
MyService.kt:
override fun onCreate() {
super.onCreate()
Log.d(TAG, "onCreate()")
doMyTask()
}
private fun doMyTask() {
job = CoroutineScope(Dispatchers.IO).launch {
// Perform task here and once complete stop service
stopSelf()
}
}
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy()")
job?.cancel()
job = null
}