Search code examples
androidandroid-intentalarmmanagerandroid-alarmsrepeatingalarm

How do I configure my AlarmReceiver to actually trigger at my desired interval?


The goal for this portion of my app is to run a repeating alarm in the background at all times that grabs a new prediction every 15 minutes from a server side machine learning algorithm, updating the app.

I currently have the skeleton for this desired behavior implemented, to make sure my methodology correct. This skeleton is supposed to trigger a toast every 10 seconds stating the alarm is working. However, after I initially set my alarm, I never see another message. I have also included a write to the console, but this never appears as well, leading me to believe that I do not entirely understand how the alarm receiver works.

Here is my main activity class that instantiates the alarm and receiver:

public class MainActivity extends AppCompatActivity implements
        TimePickerFragment.FragmentCallbacks {

    private PendingIntent pendingIntent;
    private AlarmManager manager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Retrieve a PendingIntent that will perform a broadcast
        Intent alarmIntent = new Intent(this, PredictionUpdateReceiver.class);
        pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
        startAlarm();

        //...
    }

    //...

    public void startAlarm() {
        manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        int interval = 10000;

        manager.setRepeating(AlarmManager.RTC_WAKEUP,
                System.currentTimeMillis(), interval, pendingIntent);
        Toast.makeText(this, "Alarm Set", Toast.LENGTH_SHORT).show();
    }
}

Here is my alarm receiver class:

public class PredictionUpdateReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context arg0, Intent arg1) {
        // For our recurring task, we'll just display a message
        Toast.makeText(arg0, "I'm running", Toast.LENGTH_SHORT).show();
        System.out.print("Alarm activated");

    }

}

And I have updated my manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.habitabilitystudy"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="11"
        android:targetSdkVersion="22" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <receiver android:name=".PredictionUpdateReceiver"></receiver>
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Solution

  • Well, you have a couple of issues.

    First, setRepeating() is inexact on Android 4.4 and higher, with a targetSdkVersion of 19 or higher. They do not state how "inexact" it actually is, and so I don't know when your alarms will get scheduled.

    Second, a repeating alarm period of less than one minute is not allowed on Android 5.1+, due to an undocumented regression. Periods under a minute will be rounded up to one minute. So, you will not get control in 10 seconds regardless of the inexactness.

    Finally, changes coming in the next version of Android means that you are not going to get control periodically for very long while the device is idle (and not charging) or if the user does not return to your app for a long time (while the device is not charging). That's not affecting you right now, but you may wish to ponder whether your approach to whatever it is that you are doing will work going forward.

    You can use adb shell dumpsys alarm to see if your alarm is scheduled. Unfortunately, unless they fixed things, it will not tell you when your alarm will actually run, due to the inexactness issue.

    Also, I recommend using Log.d(), or at worst System.out.println(), instead of System.out.print().