I'm encountering an issue with scheduling a foreground service using AlarmManager in my Android application. Despite setting up the code to trigger a foreground service at specific times using alarms, the alarms are unable to start foreground Service when the app is not in the background (it works fine when the app is in the foreground or in the background).
I have a requirement in my app to execute a foreground service at a specific time range of the day. To achieve this, I'm using AlarmManager to schedule the service to start and stop at the desired intervals.
and what are the different ways other than alarmManager, to schedule a foreground service.
TimeBasedScheduler Class:
class TimeBasedScheduler : BroadcastReceiver() {
private val TAG = "TimeBasedScheduler"
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
Log.d(TAG, "Received action: $action")
if (action != null) {
when (action) {
"START_SERVICE" -> {
Log.d(TAG, "Initializing socket for START_SERVICE")
initializeSocket(context)
// Now execution is started and resumed
LocalPrefrenceUtils.insertDataInBoolean(context, AppConstants.BACKGROUND_WORK_ALLOWED_KEY_FOR_LOCAL_PREFERENCE, true)
LocalPrefrenceUtils.insertDataInBoolean(context, AppConstants.BACKGROUND_WORK_TEMPORARILY_PAUSED_KEY_FOR_LOCAL_PREFERENCE, false
)
}
"STOP_SERVICE" -> {
Log.d(TAG, "Stopping service for STOP_SERVICE")
LocalPrefrenceUtils.insertDataInBoolean(
context,
AppConstants.BACKGROUND_WORK_TEMPORARILY_PAUSED_KEY_FOR_LOCAL_PREFERENCE,
true
)
val stopIntent = Intent(context, SocketManagerService::class.java)
context.stopService(stopIntent)
}
}
}
}
private fun initializeSocket(context: Context?) {
Log.d(TAG, "Initializing socket")
val intent = Intent(context, SocketManagerService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Log.d(TAG, "Starting foreground service")
context?.startForegroundService(intent)
} else {
Log.d(TAG, "Starting service")
context?.startService(intent)
}
}
}
SettingActivity Class:
private fun setupForegroundServiceAlarms() {
val TAG = "TaskBasedScheduler"
// Get the start and end times from preferences
val startTime = LocalPrefrenceUtils.getStartTime(this)
val endTime = LocalPrefrenceUtils.getEndTime(this)
Log.d(TAG, "Start Time: $startTime")
Log.d(TAG, "End Time: $endTime")
// Calculate start and end times based on step sizes and special cases for value 48
val startHour = 7 // Starting hour (7:00 am)
val stepSizeMinutes = 30 // Step size in minutes
val startHourForAlarms = startHour + (stepSizeMinutes * startTime) / 60
val endHourForAlarms = if (endTime == 48) startHour + (stepSizeMinutes * endTime) / 60 - 1 else startHour + (stepSizeMinutes * endTime) / 60
val startMinute = (stepSizeMinutes * startTime) % 60
val endMinute = if (endTime == 48) ((stepSizeMinutes * endTime) % 60) - 1 else ((stepSizeMinutes * endTime) % 60)
// Set the Calendar instances for start and end times
val startCalendar = Calendar.getInstance().apply {
timeInMillis = System.currentTimeMillis()
set(Calendar.HOUR_OF_DAY, startHourForAlarms)
set(Calendar.MINUTE, startMinute)
set(Calendar.SECOND, 0)
}
val endCalendar = Calendar.getInstance().apply {
timeInMillis = System.currentTimeMillis()
set(Calendar.HOUR_OF_DAY, endHourForAlarms)
set(Calendar.MINUTE, endMinute)
set(Calendar.SECOND, 0)
}
Log.d(TAG, "Start Calendar Time: ${startCalendar.time}")
Log.d(TAG, "End Calendar Time: ${endCalendar.time}")
// Cancel previously set alarms
alarmManager.cancel(startPendingIntent)
alarmManager.cancel(endPendingIntent)
Log.d(TAG, "Canceled previous alarms")
// Create intents for starting and stopping the service
val startIntent = Intent(this, TimeBasedScheduler::class.java).apply {
action = "START_SERVICE"
}
val endIntent = Intent(this, TimeBasedScheduler::class.java).apply {
action = "STOP_SERVICE"
}
// Create pending intents for start and end actions
startPendingIntent = PendingIntent.getBroadcast(this, 0, startIntent, PendingIntent.FLAG_IMMUTABLE)
endPendingIntent = PendingIntent.getBroadcast(this, 1, endIntent, PendingIntent.FLAG_IMMUTABLE)
Log.d(TAG, "Created pending intents")
// Set alarms using AlarmManager for daily repetition
alarmManager.setInexactRepeating(
AlarmManager.RTC_WAKEUP,
startCalendar.timeInMillis,
AlarmManager.INTERVAL_DAY,
startPendingIntent
)
alarmManager.setInexactRepeating(
AlarmManager.RTC_WAKEUP,
endCalendar.timeInMillis,
AlarmManager.INTERVAL_DAY,
endPendingIntent
)
Log.d(TAG, "Alarms set for start: ${startCalendar.time}, end: ${endCalendar.time}")
}
and manifest related code:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<receiver android:name=".schedulers.TimeBasedScheduler"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="START_SERVICE" />
<action android:name="STOP_SERVICE" />
</intent-filter>
</receiver>
works perfectly fine when the app is in the foreground or background:
Receiver when the app is in the foreground or background:
I've checked the logs using Logcat, and it doesn't show any error messages related to alarms or the foreground service not starting.
I'm seeking guidance on why the alarms are not triggering the foreground service as expected. I'd appreciate any insights, suggestions, or potential solutions to resolve this issue.
Thank you for your help.
try
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
startCalendar.timeInMillis,
startPendingIntent
)
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
endCalendar.timeInMillis,
endPendingIntent
)
} else {
// For versions below M, use setExact
alarmManager.setExact(
AlarmManager.RTC_WAKEUP,
startCalendar.timeInMillis,
startPendingIntent
)
alarmManager.setExact(
AlarmManager.RTC_WAKEUP,
endCalendar.timeInMillis,
endPendingIntent
)
}
and use alarm manager with workmanager for intervals lower than 15 min for greater than 15 min use just workmanager and set your interval and start foreground service