Android 8.0+ 如何创建/调度未来通知?
Hey Danny, totally feel your pain—jumping back into Android after a hiatus when so many old workhorses get deprecated is no fun. Let’s get you up to speed on the right tools for scheduling notifications in Android 8.0+ (API 26 and above):
1. First: Mandatory Notification Channels
Before even thinking about scheduling, you need to set up Notification Channels—Android 8.0 blocks any notifications that don’t belong to a channel. This replaces the old free-for-all notification settings, giving users granular control over notification types.
Here’s a quick implementation snippet to create a channel on app launch:
private fun createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channelId = "reminder_channel" val name = "Reminder Notifications" val descriptionText = "Notifications for scheduled reminders" val importance = NotificationManager.IMPORTANCE_DEFAULT val channel = NotificationChannel(channelId, name, importance).apply { description = descriptionText } // Register the channel with the system val notificationManager: NotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager notificationManager.createNotificationChannel(channel) } }
2. Replacing AlarmService + WakefulBroadcastReceiver: WorkManager
The old WakefulBroadcastReceiver was deprecated because it required manual wake lock management—easy to mess up and bad for battery life. WorkManager is Google’s recommended replacement for deferrable, background tasks (including notification scheduling) because:
- It handles wake locks automatically
- Adapts to system battery optimizations (like Doze mode)
- Supports one-time and periodic tasks
- Persists across device reboots (if you enable it)
Basic One-Time Notification Schedule
Let’s say you want to trigger a notification at a specific future time. First, calculate the delay between now and your target time, then use OneTimeWorkRequest:
Step 1: Create a Worker class that builds and shows the notification
class NotificationWorker(context: Context, params: WorkerParameters) : Worker(context, params) { override fun doWork(): Result { showNotification() return Result.success() } private fun showNotification() { val channelId = "reminder_channel" val notificationIntent = Intent(applicationContext, MainActivity::class.java) val pendingIntent = PendingIntent.getActivity( applicationContext, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) val notification = NotificationCompat.Builder(applicationContext, channelId) .setSmallIcon(R.drawable.ic_notification) .setContentTitle("Scheduled Reminder") .setContentText("Your scheduled task is ready!") .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setContentIntent(pendingIntent) .setAutoCancel(true) .build() val notificationManager = NotificationManagerCompat.from(applicationContext) notificationManager.notify(1, notification) } }
Step 2: Schedule the Worker from your Activity/Fragment
// Calculate delay until target time (e.g., 2 hours from now) val targetTime = System.currentTimeMillis() + (2 * 60 * 60 * 1000) val delay = targetTime - System.currentTimeMillis() val workRequest = OneTimeWorkRequestBuilder<NotificationWorker>() .setInitialDelay(delay, TimeUnit.MILLISECONDS) // Optional: Add constraints (e.g., only run when device is charging) .setConstraints(Constraints.Builder() .setRequiresCharging(false) // Adjust as needed .build()) .build() WorkManager.getInstance(applicationContext).enqueue(workRequest)
For Periodic Notifications
If you need recurring notifications (e.g., daily reminders), use PeriodicWorkRequest instead:
val periodicWork = PeriodicWorkRequestBuilder<NotificationWorker>(24, TimeUnit.HOURS) .setConstraints(Constraints.Builder() .setRequiresBatteryNotLow(true) .build()) .build() WorkManager.getInstance(applicationContext).enqueueUniquePeriodicWork( "daily_reminder", ExistingPeriodicWorkPolicy.KEEP, periodicWork )
3. Edge Case: Exact Real-Time Scheduling
If you need precise, real-time scheduling (like an alarm that can’t be delayed by Doze mode), WorkManager isn’t the best fit—use AlarmManager with setExactAndAllowWhileIdle() instead. But note that this should only be used for critical tasks, as it bypasses battery optimizations.
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager val intent = Intent(applicationContext, ExactAlarmReceiver::class.java) val pendingIntent = PendingIntent.getBroadcast( applicationContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) // Schedule for exact target time if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { alarmManager.setExactAndAllowWhileIdle( AlarmManager.RTC_WAKEUP, targetTime, pendingIntent ) } else { alarmManager.setExact(AlarmManager.RTC_WAKEUP, targetTime, pendingIntent) }
Then create a BroadcastReceiver to show the notification when the alarm triggers (but remember to request the SCHEDULE_EXACT_ALARM permission on Android 12+).
Key Takeaways
- Always use Notification Channels for Android 8.0+—no exceptions.
- WorkManager is your go-to for most scheduling needs (deferrable, battery-friendly tasks).
- Use
AlarmManageronly for critical, exact-time tasks that can’t wait.
You don’t need to hunt for outdated tutorials anymore—these are the current, Google-recommended patterns that’ll keep your app compliant and efficient post-Android 8.0.
内容的提问来源于stack exchange,提问作者DannyBoy

