Search code examples
javaandroidandroid-alarms

Android How to set exact repeating alarm?


I'm building an alarm application which will have an exact repeating alarm.

Seeing how for Repeating Android provides only Inexact alarm with possible delay of 75% of chosen interval, I've tried making Exact alarm which upon triggering sets itself once again. This type of alarm works perfectly as long as my screen is kept on. But as soon as it goes to sleep, the alarm works fine the first time, but second alarm which is set programmaticaly fires with delay as if I was using Inexact method.

As an alternative solution I'm thinking of making an InexactRepeating alarm which will fire up every minute to check whether it's "the time". This way my alarm will be with 2 minute imprecision interval, which is acceptable. But I'm not sure how much it will strain phone's battery.

Any ideas guys?

Here's my attemp at Exact alarm:

AlarmManager.java

 public static void setAlarm(Context context){
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(context.ALARM_SERVICE);

        //SET BROADCAST RECEIVER WHICH WILL BE THE ONE TO LISTEN FOR THE ALARM SIGNAL
        Intent intent = new Intent(context, AlarmTriggerBroadcastReceiver.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 22222, intent, PendingIntent.FLAG_CANCEL_CURRENT);

        //SETING THE ALARM
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            alarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 300000, pendingIntent);
        } else {
            alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 300000, pendingIntent);
        } 

    }

AlarmTriggerBroadcastReceiver.java

public class AlarmTriggerBroadcastReceiver extends BroadcastReceiver {

    private final static String TAG_ALARM_TRIGGER_BROADCAST = "ALARM_TRIGGER_BROADCAST";

    @Override
    public void onReceive(Context context, Intent intent) {
        //WAKE UP DEVICE
        WakeLocker.acquire(context);

            //LAUNCH PAGE
            Intent intent1 = new Intent();
            intent1.setClassName(context.getPackageName(), SomeActivity.class.getName());
            intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent1);


            Toast.makeText(context, "TOAST ALARM", Toast.LENGTH_LONG).show();
        };

        //SET NEW ALARM
        AlarmManagerActivity.setAlarm(context);
        WakeLocker.release();   

    }

}

WakeLocker.java

//WAKES UP DEVICE IF PHONE'S SCREEN LOCKED
public abstract class WakeLocker {
    private static PowerManager.WakeLock wakeLock;

    public static void acquire(Context ctx) {
        //if (wakeLock != null) wakeLock.release();

        PowerManager pm = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE);
        wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK |
                PowerManager.ACQUIRE_CAUSES_WAKEUP |
                PowerManager.ON_AFTER_RELEASE, "myapp:WAKE_LOCK_TAG");
        wakeLock.acquire();
    }

    public static void release() {
        if (wakeLock != null) wakeLock.release(); wakeLock = null;
    }
}

Manifest

    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
    <uses-permission android:name="android.permission.SET_ALARM"/>

  <receiver
            android:name=".Alarm.AlarmTriggerBroadcastReceiver"
            android:process=":remote">

            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"></action>
            </intent-filter>
            <intent-filter android:priority="1">
                <action android:name="my.app.here.ALARM_RECIEVED" />
            </intent-filter>
        </receiver>

What do, fellow coders?


Solution

  • have you tried using a WorkManager instead of having to use the Broadcast Receivers? See details here. And an app demo here.