Schedule Notifications on Android Using AlarmManager
Written on
Chapter 1: Introduction to Notification Scheduling
Grab a cup of coffee ☕ and join me as we explore how to leverage AlarmManager for scheduling notifications in Android.
Section 1.1: Required Dependencies
To get started, we will integrate Dagger Hilt for injecting the AppNotificationManager, which is responsible for managing notification creation. Begin by adding the following to the plugins block in your project’s build.gradle.kts:
plugins {
id("com.google.dagger.hilt.android") version "2.47" apply false
}
Next, navigate to the app/build.gradle.kts file and include:
plugins {
kotlin("kapt")
id("com.google.dagger.hilt.android")
}
dependencies {
// MARK: - Hilt
implementation("com.google.dagger:hilt-android:2.47")
kapt("com.google.dagger:hilt-android-compiler:2.47")
implementation("androidx.hilt:hilt-work:1.0.0")
implementation("androidx.work:work-runtime-ktx:2.9.0")
kapt("androidx.hilt:hilt-compiler:1.0.0")
}
Section 1.2: Creating the Notification Channel
To create a notification channel, define a YourApplication class that extends Application. This channel allows users to receive notifications, and your application can have multiple channels from which the user can select in the settings.
Make sure to annotate your application class with @HiltAndroidApp for setting up Hilt's dependency injection:
@HiltAndroidApp // Add this
class YourApplication : Application() {
override fun onCreate() {
super.onCreate()
val channel = NotificationChannel(
"food_notification", // ID
"Food", // Name
NotificationManager.IMPORTANCE_HIGH // Importance level
)
// Create the channel
val notificationManager = getSystemService(NotificationManager::class.java)
notificationManager.createNotificationChannel(channel)
}
}
Chapter 2: Setting Up Hilt
After annotating the Application class, remember to register it in your AndroidManifest.xml. Now, we will annotate MainActivity.kt with @AndroidEntryPoint and create a new object called AppModule.
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
// More to come...
}
The first video provides a detailed tutorial on how to use AlarmManager in Android Studio for scheduling notifications.
Section 2.1: Creating the AppNotificationManager
The AppNotificationManager is responsible for the notification creation logic. Here’s how to implement a basic notification:
class AppNotificationManager(
private val context: Context
) {
fun showBasicNotification(
title: String,
description: String
) {
val notification = NotificationCompat.Builder(context, "food_notification")
.setSmallIcon(R.drawable.your_logo)
.setContentTitle(title)
.setContentText(description)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true)
.build()
val notificationManager = context.getSystemService(NotificationManager::class.java)
notificationManager.notify(Random.nextInt(), notification)}
}
Subsection 2.1.1: Providing the AppNotificationManager
This ensures that the AppNotificationManager can be injected into other classes:
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
@Singleton
fun provideAppNotificationManager(
@ApplicationContext context: Context): AppNotificationManager =
AppNotificationManager(context)
}
Chapter 3: Creating the Notification Scheduler
First, define a data class for notifications that includes a title and description:
data class Notification(
val title: String = "",
val description: String = ""
)
To follow best practices, create an interface that will be implemented later:
interface NotificationScheduler {
fun schedule(notification: Notification)
}
Section 3.1: Implementing the Notification Scheduler
Now, let’s implement this interface in the AndroidNotificationScheduler class:
class AndroidNotificationScheduler(
private val context: Context
) : NotificationScheduler {
override fun schedule(notification: Notification) {
// Implementation goes here...}
}
Start by acquiring the AlarmManager, then implement the scheduling method:
private val alarmManager = context.getSystemService(AlarmManager::class.java)
Since AlarmManager requires an Intent, create one as follows:
val intent = Intent(context, NotificationReceiver::class.java)
.apply {
putExtra("TITLE", notification.title)
putExtra("DESCRIPTION", notification.description)
}
The NotificationReceiver is a BroadcastReceiver that will execute a function when it receives a call. We will inject the AppNotificationManager to display notifications:
@AndroidEntryPoint // Important
class NotificationReceiver : BroadcastReceiver() {
@Inject
lateinit var appNotificationManager: AppNotificationManager
override fun onReceive(context: Context, intent: Intent?) {
val title = intent?.getStringExtra("TITLE") ?: return
val description = intent.getStringExtra("DESCRIPTION") ?: return
appNotificationManager
.showBasicNotification(
title = title,
description = description
)
}
}
Return to the AndroidNotificationScheduler to finalize the schedule function. You can choose to display the notification at a specific time or at a less precise moment. For this tutorial, we will use setExactAndAllowWhileIdle, which guarantees the notification appears at a precise time, even in Low Power Mode:
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
LocalDateTime.now()
.plusMinutes(15)
.atZone(ZoneId.systemDefault())
.toEpochSecond() * 1000, // Multiply by 1000 for milliseconds
PendingIntent.getBroadcast(
context,
notification.hashCode(),
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
)
Ensure you resolve any errors by adding the necessary permissions, including notification permissions.
The second video demonstrates how to effectively schedule alarms on Android utilizing AlarmManager.
Section 3.2: Displaying the Notifications
In your MainActivity.kt, create a permission launcher:
val context = LocalContext.current
val notificationScheduler = remember {
AndroidNotificationScheduler(context)
}
val permissionLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.RequestPermission(),
onResult = { isGranted ->
if (isGranted) {
notificationScheduler.schedule(
notification = Notification(
title = "Food is ready",
description = "A courier is on the way"
)
)
}
}
)
Next, check if the permission is granted:
Button(
onClick = {
when (PackageManager.PERMISSION_GRANTED) {
ContextCompat.checkSelfPermission(
context,
android.Manifest.permission.POST_NOTIFICATIONS
) -> {
notificationScheduler.schedule(
notification = Notification(
title = "Food is ready",
description = "A courier is on the way"
)
)
}
else -> {
permissionLauncher.launch(
android.Manifest.permission.POST_NOTIFICATIONS)
}
}
}
) {
Text(text = "Show notification")
}
For the latest updates, feel free to follow me and subscribe to my newsletter. If you wish to see more content, don't forget to follow me on X and subscribe to my YouTube channel! Thank you for reading! 😊☕️