14

Although this question might have been asked before on Stack Overflow, I still haven't found a clear answer.

I want to show a notification everyday at 12pm for example even when the app is closed. I have referenced from those links: Notifications in specific time every day android, Android daily repeating notification at specific time of a day using AlarmManager, Android BroadcastReceiver on startup - keep running when Activity is in Background and much more... I'm confused on the difference between Service and BroadcastReceiver. Which one shall I use? or shall I use both of them?

So far, I know how to show a notification, but I don't know how to show it automatically once everyday even when the app is closed.

My code:

public class NotifyService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Toast.makeText(this, "Service created", Toast.LENGTH_LONG).show();

        Intent resultIntent = new Intent(this, HomeScreen.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0, resultIntent, 0);

        Notification.Builder notification = new Notification.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("App Title")
                .setContentText("Some Text...")
                .setContentIntent(resultPendingIntent);

        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        if (Build.VERSION.SDK_INT < 16) {
            notificationManager.notify(1, notification.getNotification());
        } else {
            notificationManager.notify(1, notification.build());
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Toast.makeText(this, "Service destroyed", Toast.LENGTH_LONG).show();
    }
}

AppManifest.xml:

<service android:name=".NotifyService" />

How should I write my code to accomplish what I want? Any suggestions or any good link that I can understand from?

Community
  • 1
  • 1
Hussein El Feky
  • 6,627
  • 5
  • 44
  • 57

3 Answers3

28

This is updated solution, and it works Android Oreo

Step 1: Create a Method in your MainActivity and use AlarmManager to set alarm at a specified time.

public void myAlarm() {
  
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.HOUR_OF_DAY, 21);
    calendar.set(Calendar.MINUTE, 47);
    calendar.set(Calendar.SECOND, 0);
    
    if (calendar.getTime().compareTo(new Date()) < 0) 
        calendar.add(Calendar.DAY_OF_MONTH, 1);

    Intent intent = new Intent(getApplicationContext(), NotificationReceiver.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
    
    if (alarmManager != null) {
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);

  }
  
}

I'm setting my alarm at 09:47 PM

Step 2: Create BroadcastReceiver to listen when the alarm happens

public class NotificationReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {

    NotificationHelper notificationHelper = new NotificationHelper(context);
    notificationHelper.createNotification();

   }
}

I'm creating this class named NotificationReceiver and extends BroadcastReceiver, in onReceive there is Class named NotificationHelper, don't confuse I will explain this Class for next steps.

Step 3: Create the Notification class

class NotificationHelper {

private Context mContext;
private static final String NOTIFICATION_CHANNEL_ID = "10001";

NotificationHelper(Context context) {
    mContext = context;
}

void createNotification()
{
   
    Intent intent = new Intent(mContext , NotificationActivity.class);
   
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

    PendingIntent resultPendingIntent = PendingIntent.getActivity(mContext,
            0 /* Request code */, intent,
            PendingIntent.FLAG_UPDATE_CURRENT);


    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mContext, NOTIFICATION_CHANNEL_ID);
    mBuilder.setSmallIcon(R.mipmap.ic_launcher);
    mBuilder.setContentTitle("Title")
            .setContentText("Content")
            .setAutoCancel(false)
            .setSound(Settings.System.DEFAULT_NOTIFICATION_URI)
            .setContentIntent(resultPendingIntent);

    NotificationManager mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O)
    {
        int importance = NotificationManager.IMPORTANCE_HIGH;
        NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "NOTIFICATION_CHANNEL_NAME", importance);
        notificationChannel.enableLights(true);
        notificationChannel.setLightColor(Color.RED);
        notificationChannel.enableVibration(true);
        notificationChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
        assert mNotificationManager != null;
        mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
        mNotificationManager.createNotificationChannel(notificationChannel);
    }
    assert mNotificationManager != null;
    mNotificationManager.notify(0 /* Request Code */, mBuilder.build());
       }
     }

This class handles the notification

Step 4: Come back to Step 2: and call the Notification Class

 NotificationHelper notificationHelper = new NotificationHelper(context);
 notificationHelper.createNotification();

Registering a BroadcastReceiver Go to your Androidmanifest file and register your broadcast receiver

<receiver
    android:name=".NotificationReceiver"></receiver>

For more info refer this guide from google

I hope it helps you.

Jimale Abdi
  • 2,574
  • 5
  • 26
  • 33
  • 4
    Thanks! But one small clarification in the code - you need to add `calendar.set(Calendar.SECOND, 0);` in Step 1. Otherwise, the alarm is triggered not exactly at the specified time, but with a delay of no more than a minute. – Gregory Dec 10 '20 at 17:56
  • 1
    @Gregory you're right the alarm will trigger between 0 to 59 Seconds, It's a random but as you mention not more than a minute. – Jimale Abdi Dec 10 '20 at 18:23
  • what about 12 hours clock time? – Abu Nayem Feb 21 '21 at 10:10
  • @JimaleAbdi can you check why this not works https://stackoverflow.com/questions/67750597/android-notification-not-comes – Shehata Gamal May 31 '21 at 17:54
  • @Sh_Khan Alarms do not fire when the device is idle in Doze mode I think that's the problem. – Jimale Abdi May 31 '21 at 18:43
  • @JimaleAbdi any workaround as this means no perfect app ? Also can job or workManager be used instead ??? – Shehata Gamal May 31 '21 at 20:34
  • 1
    The best choice of schedule repeating Alarms is using `AlarmManager`, If you must have an alarm fire even in Doze mode you can use either `setAndAllowWhileIdle()` or `setExactAndAllowWhileIdle()`. follow [this](https://developer.android.com/training/scheduling/alarms) instruction. Thanks – Jimale Abdi Jun 01 '21 at 08:19
  • If i have to schedule one at say "17:10:30" as "hh:mm:ss" daily should it be `setInexactRepeating` or `setRepeating` if i need it to fire at that time with any mode ?? – Shehata Gamal Jun 01 '21 at 11:08
  • 1
    If you want the alarm to fire an exact time consider using `setExactAndAllowWhileIdle()` also it can cause battery drain so use it with care. – Jimale Abdi Jun 01 '21 at 11:18
  • @JimaleAbdi Does `setExactAndAllowWhileIdle` repeats ?? as i need it daily – Shehata Gamal Jun 01 '21 at 14:22
  • @JimaleAbdi Also when i test and schedule notifications , i play with date and time settings to wait 1 minute for the firing as a test does that affect anything , also i use simulator will this make a difference than real device ? – Shehata Gamal Jun 01 '21 at 14:26
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/233180/discussion-between-jimale-abdi-and-sh-khan). – Jimale Abdi Jun 01 '21 at 15:15
  • What is this line for ```if (calendar.getTime().compareTo(new Date()) < 0) calendar.add(Calendar.DAY_OF_MONTH, 1);```? – Sujith S Manjavana Sep 04 '22 at 08:16
  • 1
    @SujithSManjavana This is comparing the time you defined to fire the alarm and the current time, so if the time is passed It will add a day to the calendar then the alarm will fire the next day. – Jimale Abdi Sep 04 '22 at 10:44
  • I think the only problem here is that if the android is restarted the alarm will stop working – S.Iliev Oct 10 '22 at 12:27
  • I wanted to make the answer simple so I didn't include it, you can create a new BroadcastReceiver to listen for RECEIVE_BOOT_COMPLETED. Thanks, S.Iliev. – Jimale Abdi Oct 10 '22 at 14:20
14

If I understood you correctly, I believe that you need setup a recurring alarm using AlarmManager. You also need to setup starting alarm service on device reboot. You can write a method that does what you want so it get executed when the alarm runs e.g. show notification. The following links should help you:

Musa Y.
  • 1,747
  • 18
  • 26
0
  1. Create a method which contains your code where you will define your time or at what time you want to show the notification. This method need to be called from where you want user to ask for notification.

    public void getNotification () {
    
        AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
    
        Intent intent = new Intent(getApplicationContext(), Notification_receiver.class);
    
        PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 100, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    
        intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
    
        alarmManager.cancel(pendingIntent);
    
        Calendar calendar = Calendar.getInstance();
        Calendar now = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 16);
        calendar.set(Calendar.MINUTE, 30);
        calendar.set(Calendar.SECOND, 00);
        if (now.after(calendar)) {
            Log.d("Hey","Added a day");
            calendar.add(Calendar.DATE, 1);
        }
    
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
    }
    
  2. Create a Notification_receiver class which is going to extend Broadcast Receiver here you are going to define your Channel Id. This works for API 25 and above:

    import android.app.Notification;
    import android.app.NotificationChannel;
    import android.app.NotificationManager;
    import android.app.PendingIntent;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.graphics.BitmapFactory;
    import android.media.RingtoneManager;
    import android.net.Uri;
    import android.os.Build;
    import android.util.Log;
    
    import androidx.core.app.NotificationCompat;
    
    //Created By Prabhat Dwivedi
    public class Notification_receiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            NotificationCompat.Builder builder;
            PendingIntent pendingIntent;
    
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                NotificationChannel channel = new NotificationChannel("Your App Name", "You app Package Name", NotificationManager.IMPORTANCE_HIGH);
                String channel_Id = channel.getId();
                CharSequence channel_name = channel.getName();
                Log.e("Notification_receiver", "channel_Id :" + channel_Id);
                Log.e("channel_name", "channel_name :" + channel_name);
    
                channel.setDescription("Make entry of today's spending now");      
                notificationManager.createNotificationChannel(channel);
            }
    
            builder = new NotificationCompat.Builder(context)
                    .setSmallIcon(R.drawable.yourapp_logo)
                    .setChannelId("Your app Name is your Channel Id")
                    .setContentTitle("Your title")
                    .setContentText("Your Description")
                    .setAutoCancel(true);
    
            // Under this you will find intent it is going to define after clicking notification which activity you want to redirect
            Intent repeatingIntent = new Intent(context, HomePage.class);
            pendingIntent = PendingIntent.getActivity(context, 100, repeatingIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            builder.setContentIntent(pendingIntent);
            notificationManager.notify(100, builder.build());
        }
    }
    
double-beep
  • 5,031
  • 17
  • 33
  • 41
Prabhu.d
  • 11
  • 3