0

I want to display notification every morning at 9 AM from my app.

So I am using Notification Manager, Alarm Manager, BroadcastReciever and Service to make that possible.

But I have a problem, because the notification shows randomly. When I first start the app and set the time, it works OK, but later the app fires and shows notification at random time.

How I can solve that?

Here is my code:

MainActivity

@Override
protected void onStart() {
    super.onStart();
    setAlarm();
}

public void setAlarm(){


    Calendar calendar = Calendar.getInstance();
    Calendar now = Calendar.getInstance();


    calendar.set(Calendar.HOUR_OF_DAY, 15);
    calendar.set(Calendar.MINUTE, 43);
    calendar.set(Calendar.SECOND, 0);

    if(calendar.getTime().after(now.getTime())) {
        alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);

        alarmIntent = new Intent(MainActivity.this, HoroscopeNotification.class);
        pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);


        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);        }

 }

HoroscopNotification (BroadcastReciever)

public class HoroscopeNotification extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent arg1) {
        showNotification(context);
    }

    private void showNotification(Context context) {
        Intent service1 = new Intent(context, AlarmService.class);
        context.startService(service1);
    }
}

AlarmService

public class AlarmService extends Service {
    private static final int NOTIFICATION_ID = 1;
    private NotificationManager notificationManager;
    private PendingIntent pendingIntent;

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

    @SuppressWarnings("static-access")
    @Override
    public void onStart(Intent intent, int startId)
    {
        super.onStart(intent, startId);
        Context context = this.getApplicationContext();
        notificationManager = (NotificationManager)context.getSystemService(context.NOTIFICATION_SERVICE);
        Intent mIntent = new Intent(this, MainActivity.class);
        pendingIntent = PendingIntent.getActivity(context, 0, mIntent, PendingIntent.FLAG_CANCEL_CURRENT);
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
        builder.setContentTitle("Horoskop");
        builder.setContentText("Pročitajte današnji horoskop");
        builder.setSmallIcon(R.drawable.ic_bik);
        builder.setAutoCancel(true);
        builder.setContentIntent(pendingIntent);

        notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
        notificationManager.notify(NOTIFICATION_ID, builder.build());
    }
}
ginsengtang
  • 751
  • 1
  • 7
  • 17
Zookey
  • 2,637
  • 13
  • 46
  • 80
  • You should add logs to see what is the calendar actually being registered as. That will give you a clear indication of what is actually be registered and when EXACTLY it should fire. – JoxTraex Aug 21 '15 at 15:45

2 Answers2

2

You'll notice in the Android SDK Reference material for the AlarmManager.setRepeating() states:

Note: as of API 19, all repeating alarms are inexact. If your application needs precise delivery times then it must use one-time exact alarms, rescheduling each time as described above. Legacy applications whose targetSdkVersion is earlier than API 19 will continue to have all of their alarms, including repeating alarms, treated as exact.

You need to use AlarmManager.set() on pre-APIv19 and AlarmManager.setExact() on APIv19+. When your PendingIntent is fired and you receive your Broadcast in your BroadcastReceiver.onReceive() you can set another exact alarm for the next day.

Simon
  • 10,932
  • 50
  • 49
  • Should I set alarm on activity first or somewhere else? – Zookey Aug 22 '15 at 09:22
  • Hey, where do I initially need to set alarm? – Zookey Aug 27 '15 at 08:57
  • Yes. When the user launches your app. So yes your MainActivity. – Simon Aug 27 '15 at 09:46
  • Just when he starts the app for the first time? And then on BroadcastReciever should set notification for the next day. – Zookey Aug 27 '15 at 09:48
  • Yes. It might be good to then set the methods to static and move them into a new class called DailyAlarm or something l. For organisation and clarity of code. – Simon Aug 27 '15 at 09:52
  • Just to be clear eveytime MainActivity loads it should see if a alarm has been set and if not, set one. – Simon Aug 27 '15 at 09:53
  • I have added app launch counter and save it to SharedPrefs, and if it is first launch, then I initially set the alarm. And after alarms fires then I set next alarm. Is there logic to check if alarm is active? – Zookey Aug 27 '15 at 09:54
  • Yes, you can. Read the PendingIntent documentation. – Simon Aug 27 '15 at 09:57
  • Will do, but I think that this should work OK with app counter approach? – Zookey Aug 27 '15 at 09:58
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/88087/discussion-between-simon-and-zookey). – Simon Aug 27 '15 at 10:47
  • if it's working then please share with us also. – Gaurav Mandlik Mar 19 '21 at 06:59
0

Alarm Manager Example

I think you should follow above link. From my point of view, your design pattern (setting alarm in Activity class is not a good approach). Instead (like showed in the answer above) you should set your alarm from a service. Also the code for notification goes in BroadcastReceiver class, method OnReceive (In the example it is commented "Put here YOUR code").

Good luck

Community
  • 1
  • 1
Šime Tokić
  • 700
  • 1
  • 9
  • 22