Alarm Manager to setup reminders in an Android app
Android provides AlarmManager class to run application code/events at a specific time, even if your app is not running at that time. Alarm Manager provides access to system alarm services. It holds a CPU wake lock as long as the receiver's onReceive() method is executing. Wake lock is released after the completion of onReceive() method on the receiver's side.
While using Alarm Manager first decide what type of Alarm is apt for your application. Use Exact Alarm if your application needs precisely timed alarm such as calendar app or alarm clock app. For normal scheduling of tasks/events Inexact Alarm type will work. Since exact alarms consumes great deal of system resources like battery life, it is recommended that you create inexact alarms whenever possible!
I had a use case where, I needed to create multiple alarms for my tasks in a todo app. For that, I have used AlarmManager along with Broadcast Receiver and Simple Notification. Follow the below steps to implement this functionality.
Step1: In the manifest file add below permissions.
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
Step2: Here I have created a function to invoke AlarmManager service. I have used RTC_WAKEUP as the type as per my app requirement. Other available options are RTC, ELAPSED_REALTIME and ELAPSED_REALTIME_WAKEUP.
RTC fires the pending intent at a specified time but doesn't wake up the device.
RTC_WAKEUP wakes up the device to fire pending intent at a specified time.
ELAPSED_REALTIME fires the pending intent based on the time elapsed since device reboot.
ELAPSED_REALTIME_WAKEUP wakes up the device and fires the pending intent after the specified length of time has elapsed since device reboot.
private fun callAlarmManager(taskName: String, taskDueDate: Long) {
//Defining a variable to pass unique request code for every new pendingIntent
val Id: Int = System.currentTimeMillis().toInt()
Log.d("TAG ","Id -"+Id)
alarmMgr = getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmIntent = Intent(this, AlarmReceiver::class.java).let { intent ->
intent.putExtra("Task_Name",taskName)
intent.putExtra("Id",Id)
PendingIntent.getBroadcast(this, Id, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
alarmMgr?.set(
AlarmManager.RTC_WAKEUP,
taskDueDate,
alarmIntent
)
Note: Since my requirement was to create multiple alarms at a time, I had to pass unique request code values to PendingIntent.getBroadcast method. Variable Id is created for this purpose. Same value is sent as an intent extra to the receiver, and then to the NotificationUtils class, to link it with it's respective pending Intents while building the notifications.
Step3: Create AlarmReceiver class which extends BroadcastReceiver. This class will initiate the notification upon receiving the alarm.
class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(p0: Context?, p1: Intent?) {
val taskName = p1!!.getStringExtra("Task_Name").toString()
val Id = p1.getIntExtra("Id", 0)
Log.d("TAG", "Id value "+Id)
val notificationUtils = p0?.let { NotificationUtils(it, taskName, Id) }
val notification = notificationUtils?.getNotificationBuilder()?.build()
notificationUtils?.getManager()?.notify(Id, notification)
}
}
<manifest....>
<application...>
<activity..
</activity>
<receiver android:name=".AlarmReceiver" />
</application>
</manifest>
Register your receiver in the manifest file as shown above.
Step4: Create another class called NotificationUtils as shown below to define all the methods related to notifications.
Note : For the pending Intent use the same requestcode i.e. reqId variable which stores the value of 'Id', which has been passed as the input parameter while invoking NotificationUtils from the Receiver class.
class NotificationUtils(base: Context,taskName:String,Id:Int) : ContextWrapper(base){
val CHANNEL_ID = "App Alert Notification ID"
val CHANNEL_NAME = "App Alert Notification"
val task : String = taskName
val reqId :Int = Id
private var manager: NotificationManager? = null
init {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Log.d("TAG","SDK Version "+Build.VERSION.SDK_INT)
createChannels()
}
}
// Create channel for Android version 26+
@TargetApi(Build.VERSION_CODES.O)
private fun createChannels() {
val channel = NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH)
channel.enableVibration(true)
getManager().createNotificationChannel(channel)
Log.d("TAG","Creating Notification Channel")
}
// Get Manager
fun getManager() : NotificationManager {
if (manager == null) manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
Log.d("TAG","Getting Notification Manager")
return manager as NotificationManager
}
fun getNotificationBuilder(): NotificationCompat.Builder {
val intent = Intent(this, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent = PendingIntent.getActivity(this, reqId, intent, PendingIntent.FLAG_IMMUTABLE)
return NotificationCompat.Builder(applicationContext, MYCHANNEL_ID)
.setSmallIcon(R.drawable.ic_task_reminder)
.setContentTitle("Alarm!")
.setContentText("Hello! It's time to work on your task- "+task)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setAutoCancel(true)
}
}
You can get more details on the above concepts in the following links :
Subscribe to my newsletter
Read articles from sandhya bhat directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by