How to Schedule Notification in Android
Solution 1
You need to use PendingIntent
and BroadCastReceiver
for this -
public void scheduleNotification(Context context, long delay, int notificationId) {//delay is after how much time(in millis) from current time you want to schedule the notification
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setContentTitle(context.getString(R.string.title))
.setContentText(context.getString(R.string.content))
.setAutoCancel(true)
.setSmallIcon(R.drawable.app_icon)
.setLargeIcon(((BitmapDrawable) context.getResources().getDrawable(R.drawable.app_icon)).getBitmap())
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));
Intent intent = new Intent(context, YourActivity.class);
PendingIntent activity = PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_CANCEL_CURRENT);
builder.setContentIntent(activity);
Notification notification = builder.build();
Intent notificationIntent = new Intent(context, MyNotificationPublisher.class);
notificationIntent.putExtra(MyNotificationPublisher.NOTIFICATION_ID, notificationId);
notificationIntent.putExtra(MyNotificationPublisher.NOTIFICATION, notification);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, notificationId, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
long futureInMillis = SystemClock.elapsedRealtime() + delay;
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, futureInMillis, pendingIntent);
}
Also, you need to show notification in your receiver class -
public class MyNotificationPublisher extends BroadcastReceiver {
public static String NOTIFICATION_ID = "notification_id";
public static String NOTIFICATION = "notification";
@Override
public void onReceive(final Context context, Intent intent) {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = intent.getParcelableExtra(NOTIFICATION);
int notificationId = intent.getIntExtra(NOTIFICATION_ID, 0);
notificationManager.notify(notificationId, notification);
}
}
Finally, call scheduleNotification()
with appropriate arguments and you are good to go!
Solution 2
NOT FOR USE IN OREO+ (edit)
The answers above are good - but don't consider the user's potential to restart the device (which clears PendingIntent's scheduled by AlarmManager).
You need to create a WakefulBroadcastReceiver, which will contain an AlarmManager to schedule deliver a PendingIntent. When the WakefulBroadcastReceiver handles the intent - post your notification and signal the WakefulBroadcastReceiver to complete.
WakefulBroadcastReceiver
/**
* When the alarm fires, this WakefulBroadcastReceiver receives the broadcast Intent
* and then posts the notification.
*/
public class WakefulReceiver extends WakefulBroadcastReceiver {
// provides access to the system alarm services.
private AlarmManager mAlarmManager;
public void onReceive(Context context, Intent intent) {
//// TODO: post notification
WakefulReceiver.completeWakefulIntent(intent);
}
/**
* Sets the next alarm to run. When the alarm fires,
* the app broadcasts an Intent to this WakefulBroadcastReceiver.
* @param context the context of the app's Activity.
*/
public void setAlarm(Context context) {
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, WakefulReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
//// TODO: use calendar.add(Calendar.SECOND,MINUTE,HOUR, int);
//calendar.add(Calendar.SECOND, 10);
//ALWAYS recompute the calendar after using add, set, roll
Date date = calendar.getTime();
mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, date.getTime(), alarmIntent);
// Enable {@code BootReceiver} to automatically restart when the
// device is rebooted.
//// TODO: you may need to reference the context by ApplicationActivity.class
ComponentName receiver = new ComponentName(context, BootReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
}
/**
* Cancels the next alarm from running. Removes any intents set by this
* WakefulBroadcastReceiver.
* @param context the context of the app's Activity
*/
public void cancelAlarm(Context context) {
Log.d("WakefulAlarmReceiver", "{cancelAlarm}");
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, WakefulReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
mAlarmManager.cancel(alarmIntent);
// Disable {@code BootReceiver} so that it doesn't automatically restart when the device is rebooted.
//// TODO: you may need to reference the context by ApplicationActivity.class
ComponentName receiver = new ComponentName(context, BootReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
BootReceiver
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
context = ApplicationActivity.class;
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, WakefulReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
//// TODO: use calendar.add(Calendar.SECOND,MINUTE,HOUR, int);
//calendar.add(Calendar.SECOND, 10);
//ALWAYS recompute the calendar after using add, set, roll
Date date = calendar.getTime();
alarmManager.setExact(AlarmManager.RTC_WAKEUP, date.getTime(), alarmIntent);
}
}
}
AndroidManifest.xml
<receiver android:name=".WakefulReceiver"/>
<receiver android:name=".BootReceiver"
android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
OmerN
Updated on July 09, 2022Comments
-
OmerN almost 2 years
I'm trying to set notification for a time in the future. I have the code for creating a notification but I can't find an option to schedule it.
How can I schedule notifications?
-
Si8 over 7 yearsso everyday at 12PM for example... are those code going in main activity?
-
NghiaDao over 7 yearsThis code scheduled alarm will be cancel when app is swipe in "recent apps list". How do avoid this issue?
-
Rafal Zawadzki over 7 yearsThis is gold! Glad to find it.
-
SARose about 7 yearsHey on the
BootReceiver.class
you shouldn't use manually type "android.intent.action.BOOT_COMPLETED" rather useIntent.ACTION_BOOT_COMPLETED
-
Aaron Smentkowski about 7 yearsSeems like the accepted answer should be the one below by apelsoczi.. Seems relatively useless to schedule a notification without a guarantee of delivery on the scheduled date if the phone is restarted.
-
Pelanes about 7 yearsRemember to add permission into Manifest file <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
-
MartinGian almost 7 yearsHey, this works even if the app is not running at the moment of the notification? Thanks
-
apelsoczi almost 7 years@MartinGian yes it does, following the parameter annotation reference for WakefulBroadcastReceiver#setAlarm
@param context the context of the app's Activity.
-
DevAndroid over 6 yearsWakefulBroadcastReceiver is deprecated in Android 8.0. Hence this solution may not work for Android 8.0
-
apelsoczi over 6 yearsthanks, i think you can simply use a broadcast receiver - will revisit this answer and remove disclaimer at top of post
-
outofthecave over 6 yearsThe solution for Android 8 Oreo seems to be to extend
BroadcastReceiver
instead ofWakefulBroadcastReceiver
, see stackoverflow.com/a/45825690/5824489 -
stillwaiting about 6 yearsThis answer is INCORRECT, because you are putting images to the intent. This is anti-pattern and might cause errors. Please have a lookt at: stackoverflow.com/questions/23407821/…
-
AJW about 6 years@SARose Hi, can you explain why you recommended using ".ACTION_BOOT_COMPLETED" rather than ".BOOT_COMPLETED"?
-
Orientos over 5 yearsis YourActivity.class the caller activity? the solution did not work
-
Shadab Ansari over 5 years
YourActivity
is the activity you want to launch when user taps on the notification. -
Allan Veloso about 5 yearsCan anyone edit with an explanation of why It should not be used in SDK 26+?
-
enarcee about 5 yearsWon't work unless you add the following in AndroidManifest.xml
<receiver android:name=".MyNotificationPublisher" />
under<application>
tag. Note, MyNotificationPublisher.java is in the same folder. -
grrigore almost 5 yearsWhat is ApplicationActivity.class?
-
AZ_ about 4 years