Search code examples
androidfragmentalarmmanager

Working repeating alarmmanager doesn't work, receiver doesn't start


public void schedule()
{
    Long time = new GregorianCalendar().getTimeInMillis()+10*1000;
    Intent intent = new Intent(getActivity(), AlarmReceiver.class);
    AlarmManager alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
    alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, time, 10*1000, PendingIntent.getBroadcast(getActivity(), 1,  intent, PendingIntent.FLAG_UPDATE_CURRENT));
}

Above this is my method in a Fragment. Also tried in Activity. Weirdly this code works on an empty test project. The problem as I've seen here is that the last part, alarmManager.setInexactRepeating() does not start the AlarmReceiver.class at all.

What am I doing wrong here?

my Manifest file:

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

also my receiver:

public class AlarmReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent){
        Toast.makeText(context, "Alarm Triggered and SMS Sent", Toast.LENGTH_LONG).show();
    }
}

Solution

  • Because of setInexactRepeating. Use setRepeating and it will be processed at the right time.

    Instead of:

    setInexactRepeating 
    

    use

    setRepeating
    

    setInexactRepeating, is OS and battery friendly, it batches together all the work to be done on Alarm receive and works through one by one, while as setRepeating instantly fires the alarm

    Also a note: Alarms are wiped off once phone is rebooted, you might have to implement a boot broadcast receiver to make it persistent. Make sure you dont do that runtime, you need to implement it in the Manifest else when your app is not in background you will not receive any broadcasts.

    A small example:

    This is working code. It wakes CPU every 10 minutes until the phone turns off.

    Add to Manifest.xml:

    ...
    <uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
    ...
    <receiver  android:process=":remote" android:name="Alarm"></receiver>
    ...
    

    Code:

        package YourPackage;
        import android.app.AlarmManager;
        import android.app.PendingIntent;
        import android.content.BroadcastReceiver;
        import android.content.Context;
        import android.content.Intent;
        import android.os.PowerManager;
        import android.widget.Toast;
    
        public class Alarm extends BroadcastReceiver 
        {    
             @Override
             public void onReceive(Context context, Intent intent) 
             {   
                 PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
                 PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
                 wl.acquire();
    
                 // Put here YOUR code.
                 Toast.makeText(context, "Alarm !!!!!!!!!!", Toast.LENGTH_LONG).show(); // For example
    
                 wl.release();
             }
    
         public void SetAlarm(Context context)
         {
             AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
             Intent i = new Intent(context, Alarm.class);
             PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
             am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60 * 10, pi); // Millisec * Second * Minute
         }
    
         public void CancelAlarm(Context context)
         {
             Intent intent = new Intent(context, Alarm.class);
             PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
             AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
             alarmManager.cancel(sender);
         }
     }
    

    Set Alarm from Service:

    package YourPackage;
    import android.app.Service;
    import android.content.Context;
    import android.content.Intent;
    import android.os.IBinder;
    
    public class YourService extends Service
    {
        Alarm alarm = new Alarm();
        public void onCreate()
        {
            super.onCreate();       
        }
    
        public void onStart(Context context,Intent intent, int startId)
        {
            alarm.SetAlarm(context);
        }
    
        @Override
        public IBinder onBind(Intent intent) 
        {
            return null;
        }
    }
    

    If you want set alarm repeating at phone boot time:

    Add permission to Manifest.xml:

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission>
    ...
    <receiver android:name=".AutoStart">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"></action>
        </intent-filter>
    </receiver>
    ...
    

    And create new class:

    package YourPackage;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    
    public class AutoStart extends BroadcastReceiver
    {   
        Alarm alarm = new Alarm();
        @Override
        public void onReceive(Context context, Intent intent)
        {   
            if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED"))
            {
                alarm.SetAlarm(context);
            }
        }
    }