How to Schedule Notification in Android

56,143

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>
Share:
56,143
OmerN
Author by

OmerN

Updated on July 09, 2022

Comments

  • OmerN
    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
    Si8 over 7 years
    so everyday at 12PM for example... are those code going in main activity?
  • NghiaDao
    NghiaDao over 7 years
    This code scheduled alarm will be cancel when app is swipe in "recent apps list". How do avoid this issue?
  • Rafal Zawadzki
    Rafal Zawadzki over 7 years
    This is gold! Glad to find it.
  • SARose
    SARose about 7 years
    Hey on the BootReceiver.class you shouldn't use manually type "android.intent.action.BOOT_COMPLETED" rather use Intent.ACTION_BOOT_COMPLETED
  • Aaron Smentkowski
    Aaron Smentkowski about 7 years
    Seems 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
    Pelanes about 7 years
    Remember to add permission into Manifest file <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  • MartinGian
    MartinGian almost 7 years
    Hey, this works even if the app is not running at the moment of the notification? Thanks
  • apelsoczi
    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
    DevAndroid over 6 years
    WakefulBroadcastReceiver is deprecated in Android 8.0. Hence this solution may not work for Android 8.0
  • apelsoczi
    apelsoczi over 6 years
    thanks, i think you can simply use a broadcast receiver - will revisit this answer and remove disclaimer at top of post
  • outofthecave
    outofthecave over 6 years
    The solution for Android 8 Oreo seems to be to extend BroadcastReceiver instead of WakefulBroadcastReceiver, see stackoverflow.com/a/45825690/5824489
  • stillwaiting
    stillwaiting about 6 years
    This 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
    AJW about 6 years
    @SARose Hi, can you explain why you recommended using ".ACTION_BOOT_COMPLETED" rather than ".BOOT_COMPLETED"?
  • Orientos
    Orientos over 5 years
    is YourActivity.class the caller activity? the solution did not work
  • Shadab Ansari
    Shadab Ansari over 5 years
    YourActivity is the activity you want to launch when user taps on the notification.
  • Allan Veloso
    Allan Veloso about 5 years
    Can anyone edit with an explanation of why It should not be used in SDK 26+?
  • enarcee
    enarcee about 5 years
    Won'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
    grrigore almost 5 years
    What is ApplicationActivity.class?
  • AZ_
    AZ_ about 4 years