skip to Main Content

I have this code in my class:

public void setAlarm(Context context)
{
    AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(context, StepCountUpdaterAlarm.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);

    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.HOUR_OF_DAY, 23);
    calendar.set(Calendar.MINUTE, 59);
    calendar.set(Calendar.SECOND, 59);
    Long startOfTommorowMillis = calendar.getTimeInMillis();

    calendar.set(Calendar.HOUR_OF_DAY, 0);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    Long startOfTodayMillis = calendar.getTimeInMillis();

    calendar.set(Calendar.HOUR_OF_DAY, 6);
    calendar.set(Calendar.MINUTE, 30);
    calendar.set(Calendar.SECOND, 0);
    Long startOfAlarmMillis = calendar.getTimeInMillis() - startOfTodayMillis;

    Long totalWaitMillis = (startOfTodayMillis + startOfAlarmMillis) - System.currentTimeMillis();

    if(totalWaitMillis < 0) return;
    if (android.os.Build.VERSION.SDK_INT >= 23) {
        alarmManager.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,
                totalWaitMillis,
                pendingIntent);
    } else {
        alarmManager.set(AlarmManager.RTC_WAKEUP,
                totalWaitMillis,
                pendingIntent);
    }
}

What I am trying to do is to have this alarm fire at 6:30am UTC every day. To do that I use Long totalWaitMillis = (startOfTomorrowMillis + startOfAlarmMillis) - System.currentTimeMillis(); but for testing purposes, i changed it to use startOfTodayMillis so i can test the alarm.
I managed to get the calendar to show the correct firing times with startOfTodayMillis - startOfAlarmMillis. When i subtract System.currentTimeMillis(), it seems to provide the correct amount of millisecond delay for the alarm to fire next. In effect, it calculates the time in milliseconds till it hits 6:30 today (I have not fired it in the past in this scenario). Yet despite this, it fires extremely early and does its task far earlier than expected. When I use startOfTomorrowMillis + startOfAlarmMillis as well, it fires practically a day early and multiple times. I am a novice when it comes to working with AlarmManager so any help here would be appreciated.

EDIT: I am aware that these alarm timers are not exact. I expected a few seconds offset but not minutes or near enough a day. To add a bit of detail, I just tried setting the alarm an hour from now, it fired at least 5 times within around 20 seconds, after an initial 30 seconds from the alarm being set. My device currently uses the setAndAllowWhileIdle method.

2

Answers


  1. Chosen as BEST ANSWER

    The method shown in the question was to have the alarm work in idle but to repeat itself which is not a feature i have seen available in the AlarmManager from reading its documentation.

    My initial misconception with the AlarmManager was that the setAndAllowWhileIdle and set methods's second parameter Long triggerAtMillis wasn't a count down to the next time it should fire the alarm, it was the actual time it should fire for the next alarm. The documentation for the triggerAtMillis parameter shown here and below:

    triggerAtMillis: time in milliseconds that the alarm should go off, using the appropriate clock (depending on the alarm type).

    Courtesy of @Niaj Mahmud 's I have made my own twist to the answer he provided that works such that it does a scheduled task while the phone is in doze mode/ is idle. In this example I schedule the task at 11:58pm of each day, without the need for a notification.

    Activity.java code:

        public void setAlarm(Context context)
        {
            AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
            Intent intent = new Intent(context, StepCountUpdaterAlarm.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
            PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
    
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.HOUR_OF_DAY, 23);
            calendar.set(Calendar.MINUTE, 58);
            calendar.set(Calendar.SECOND, 0);
            if (calendar.getTimeInMillis() < System.currentTimeMillis()) {
                calendar.add(Calendar.DAY_OF_YEAR, 1);
            }
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                alarmManager.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
            } else {
                alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
            }
        }
    

    BroadcastReciever.java code

        @Override
        public void onReceive(Context context, Intent intent) {
            MyActivity myActivity = MyActivity.getInstance();
            //Do your work here.
           
            myActivity.setAlarm(context); //Set your alarm again to reschedule itself.
        }
    

  2. For recurring alarm why you are doing like that.. alarm manager already has own method for alarm in every 24 hour.

    first create a class with broadcast receiver like

                    class AlarmReceiver : BroadcastReceiver() {
                    
                        override fun onReceive(context: Context, intent: Intent?) {
                            Log.d("this", "notify")
                    
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    
                                val intent = Intent(context, AlarmActivity2::class.java)
                                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
                                val pendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
                    
                                val builder = NotificationCompat.Builder(context, "111")
                                    .setSmallIcon(R.drawable.blue_stringart)
                                    .setContentTitle("Alarm is running")
                                    .setAutoCancel(true)
                                    .setDefaults(NotificationCompat.DEFAULT_ALL)
                                    .setDefaults(NotificationCompat.DEFAULT_SOUND)
                                    .setDefaults(NotificationCompat.DEFAULT_VIBRATE)
                                    .setPriority(NotificationCompat.PRIORITY_HIGH)
                                    .addAction(R.drawable.ic_baseline_stop_24,"Stop",pendingIntent)
                                    .setContentIntent(pendingIntent)
                    
                                val notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM)
                                val r = RingtoneManager.getRingtone(context, notification)
                                r.play()
                    
                                val notificationManagerCompat = NotificationManagerCompat.from(context)
                                notificationManagerCompat.notify(123, builder.build())
                    
                            }
                    
                        }
                    
                    } 
            
    

    after that go to your activity class make 2 method and call in oncreate

                private fun setAlarm1() {
                var calender: Calendar
              calender = Calendar.getInstance()
                            calender.set(Calendar.HOUR_OF_DAY, PUT_YOUR_ALARM HOUR)
                            calender.set(Calendar.MINUTE, PUT_YOUR_ALARM MINUTE)
                            calender.set(Calendar.SECOND, 0)
                        alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
                        val thuReq: Long = Calendar.getInstance().timeInMillis + 1
                        var reqReqCode = thuReq.toInt()
                        if (calender.timeInMillis < System.currentTimeMillis()) {
                            calender.add(Calendar.DAY_OF_YEAR, 1)
                        }
                        val alarmTimeMilsec = calender.timeInMillis
                        val intent = Intent(this, AlarmReceiver::class.java)
                        intent.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
                        val pendingIntent = PendingIntent.getBroadcast(this, reqReqCode, intent, 0)
                
                        alarmManager.setRepeating(
                            AlarmManager.RTC_WAKEUP,
                            calender.timeInMillis,
                           24 * 60 * 60 * 1000,// or AlarmManager.INTERVAL_DAY
                            pendingIntent
                        )
        
        
            private fun createNotificationChannel() {
        
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    val name = "Alarmclock Channel"
                    val description = " Reminder Alarm manager"
                    val importance = NotificationManager.IMPORTANCE_HIGH
                    val notificationChannel = NotificationChannel(CHANNELID, name, importance)
                    notificationChannel.description = description
                    val notificationManager =
                        getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
                    notificationManager.createNotificationChannel(notificationChannel)
                }
            }
    

    Note – Must to do(go to your app setting and give notification permission on) 1.alarmManager.setRepeating here you can use your alarm type as your wish. 2.requestcode must be unique for each alarm. 3. you must take a alarm time and keep in calender.timeInMillis which is you expecting alarm time.

    still problem comments below

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search