Katie McCormick | 7bdb3f6 | 2013-09-05 14:46:20 -0700 | [diff] [blame] | 1 | page.title=Scheduling Repeating Alarms |
| 2 | parent.title=Using Wake Locks |
| 3 | parent.link=index.html |
| 4 | |
| 5 | trainingnavtop=true |
| 6 | |
| 7 | @jd:body |
| 8 | |
| 9 | <div id="tb-wrapper"> |
| 10 | <div id="tb"> |
| 11 | |
| 12 | <!-- table of contents --> |
| 13 | <h2>This lesson teaches you to</h2> |
| 14 | <ol> |
Katie McCormick | 49f9348 | 2014-02-07 14:33:10 -0800 | [diff] [blame] | 15 | <li><a href="#tradeoffs">Understand the Trade-offs</a></li> |
Katie McCormick | 7bdb3f6 | 2013-09-05 14:46:20 -0700 | [diff] [blame] | 16 | <li><a href="#set">Set a Repeating Alarm</a></li> |
| 17 | <li><a href="#cancel">Cancel an Alarm</a></li> |
| 18 | <li><a href="#boot">Start an Alarm When the Device Boots</a></li> |
| 19 | </ol> |
| 20 | |
| 21 | <h2>Try it out</h2> |
| 22 | |
| 23 | <div class="download-box"> |
| 24 | <a href="{@docRoot}shareables/training/Scheduler.zip" |
| 25 | class="button">Download the sample</a> |
| 26 | <p class="filename">Scheduler.zip</p> |
| 27 | </div> |
| 28 | |
| 29 | </div> |
| 30 | </div> |
| 31 | |
Katie McCormick | 49f9348 | 2014-02-07 14:33:10 -0800 | [diff] [blame] | 32 | <a class="notice-developers-video wide" href="http://www.youtube.com/watch?v=yxW29JVXCqc"> |
| 33 | <div> |
| 34 | <h3>Video</h3> |
| 35 | <p>The App Clinic: Cricket</p> |
| 36 | </div> |
| 37 | </a> |
| 38 | |
| 39 | <a class="notice-developers-video wide" |
| 40 | href="https://www.youtube.com/playlist?list=PLWz5rJ2EKKc-VJS9WQlj9xM_ygPopZ-Qd"> |
| 41 | <div> |
| 42 | <h3>Video</h3> |
| 43 | <p>DevBytes: Efficient Data Transfers</p> |
| 44 | </div> |
| 45 | </a> |
| 46 | |
Katie McCormick | 7bdb3f6 | 2013-09-05 14:46:20 -0700 | [diff] [blame] | 47 | <p>Alarms (based on the {@link android.app.AlarmManager} class) give you a way to perform |
| 48 | time-based operations outside the lifetime of your application. |
| 49 | For example, you could use an alarm to initiate a long-running operation, such |
| 50 | as starting a service once a day to download a weather forecast.</p> |
| 51 | |
| 52 | <p>Alarms have these characteristics:</p> |
| 53 | <ul> |
| 54 | |
| 55 | <li>They let you fire Intents at set times and/or intervals.</li> |
| 56 | |
| 57 | <li>You can use them in conjunction with broadcast receivers to start services and perform |
| 58 | other operations.</li> |
| 59 | |
| 60 | <li>They operate outside of your application, so you can use them to trigger events or |
| 61 | actions even when your app is not running, and even if the device itself is asleep.</li> |
| 62 | |
| 63 | <li>They help you to minimize your app's resource requirements. You can schedule operations |
| 64 | without relying on timers or continuously running background services.</li> |
| 65 | |
| 66 | </ul> |
| 67 | |
| 68 | <p class="note"><strong>Note:</strong> For timing operations that are guaranteed to occur |
| 69 | <em>during</em> the lifetime of your application, |
| 70 | instead consider using the {@link android.os.Handler} class in conjunction with |
| 71 | {@link java.util.Timer} and {@link java.lang.Thread}. This approach gives Android better |
| 72 | control over system resources.</p> |
| 73 | |
Katie McCormick | 49f9348 | 2014-02-07 14:33:10 -0800 | [diff] [blame] | 74 | <h2 id="tradeoffs">Understand the Trade-offs</h2> |
| 75 | |
| 76 | <p>A repeating alarm is a relatively simple mechanism with limited flexibility. |
| 77 | It may |
| 78 | not be the best choice for your app, particularly if you need to trigger network |
| 79 | operations. A poorly designed alarm can cause battery drain and put a significant load on |
| 80 | servers.</p> |
| 81 | |
| 82 | <p>A common scenario for triggering an operation outside the lifetime of your app is |
| 83 | syncing data with a server. This is a case where you might be tempted to use a |
| 84 | repeating alarm. But if you own the server that is hosting your app's |
| 85 | data, using <a href="{@docRoot}google/gcm/index.html">Google Cloud Messaging</a> (GCM) |
| 86 | in conjunction with <a href="{@docRoot}training/sync-adapters/index.html">sync adapter</a> |
| 87 | is a better solution than {@link android.app.AlarmManager}. A sync adapter gives you all |
| 88 | the same scheduling options as {@link android.app.AlarmManager}, but it offers |
| 89 | you significantly more flexibility. For example, |
| 90 | a sync could be based on a "new data" message from the server/device (see |
| 91 | <a href="{@docRoot}training/sync-adapters/running-sync-adapter.html">Running a Sync |
| 92 | Adapter</a> for details), the user's activity (or inactivity), the time of day, and so on. |
| 93 | See the linked videos at the top of this page for a detailed discussion of when and how |
| 94 | to use GCM and sync adapter.</p> |
| 95 | |
| 96 | <h3>Best practices</h3> |
| 97 | |
| 98 | <p>Every choice you make in designing your repeating alarm can have consequences in how your |
| 99 | app uses (or abuses) system resources. For example, imagine a popular app that |
| 100 | syncs with a server. If the sync operation is based on clock time and every instance of the |
| 101 | app syncs at 11:00 p.m., the load on the server could result in high latency or even |
| 102 | "denial of service." Follow these best practices in using alarms:</p> |
| 103 | |
| 104 | <ul> |
| 105 | <li>Add randomness (jitter) to any network requests that |
| 106 | trigger as a result of a repeating alarm: |
| 107 | <ul> |
| 108 | <li>Do any local work when the alarm triggers. "Local work" means anything that doesn't |
| 109 | hit a server or require the data from the server.</li> |
| 110 | <li>At the same time, schedule the alarm that contains the network requests to fire at some |
| 111 | random period of time.</li> </ul></li> |
| 112 | |
| 113 | |
| 114 | <li>Keep your alarm frequency to a minimum.</li> |
| 115 | <li>Don't wake up the device unnecessarily (this behavior is determined by the alarm type, |
| 116 | as described in <a href="#type">Choose an alarm type</a>).</li> |
| 117 | <li>Don't make your alarm's trigger time any more precise than it has to be. |
| 118 | |
| 119 | |
| 120 | <p>Use {@link android.app.AlarmManager#setInexactRepeating setInexactRepeating()} instead |
| 121 | of {@link android.app.AlarmManager#setRepeating setRepeating()}. |
| 122 | When you use {@link android.app.AlarmManager#setInexactRepeating setInexactRepeating()}, |
| 123 | Android synchronizes repeating alarms from multiple apps and fires |
| 124 | them at the same time. This reduces the total number of times the system must wake the |
| 125 | device, thus reducing drain on the battery. As of Android 4.4 |
| 126 | (API Level 19), all repeating alarms are inexact. Note that while |
| 127 | {@link android.app.AlarmManager#setInexactRepeating setInexactRepeating()} is an |
| 128 | improvement over {@link android.app.AlarmManager#setRepeating setRepeating()}, it can |
| 129 | still overwhelm a server if every instance of an app hits the server around the same time. |
| 130 | Therefore, for network requests, add some randomness to your alarms, as discussed above.</p> |
| 131 | </li> |
| 132 | |
| 133 | <li>Avoid basing your alarm on clock time if possible. |
| 134 | |
| 135 | <p>Repeating alarms that are based on a precise trigger time don't scale well. |
| 136 | Use {@link android.app.AlarmManager#ELAPSED_REALTIME} if you can. The different alarm |
| 137 | types are described in more detail in the following section.</p> |
| 138 | |
| 139 | </li> |
| 140 | |
| 141 | </ul> |
| 142 | |
| 143 | |
Katie McCormick | 7bdb3f6 | 2013-09-05 14:46:20 -0700 | [diff] [blame] | 144 | <h2 id="set">Set a Repeating Alarm</h2> |
| 145 | |
| 146 | <p>As described above, repeating alarms are a good choice for scheduling regular events or |
| 147 | data lookups. A repeating alarm has the following characteristics:</p> |
| 148 | |
| 149 | <ul> |
| 150 | <li>A alarm type. For more discussion, see <a href="#type">Choose an alarm type</a>.</li> |
| 151 | <li>A trigger time. If the trigger time you specify is in the past, the alarm triggers |
| 152 | immediately.</li> |
| 153 | <li>The alarm's interval. For example, once a day, every hour, every 5 seconds, and so on.</li> |
| 154 | <li>A pending intent that fires when the alarm is triggered. When you set a second alarm |
| 155 | that uses the same pending intent, it replaces the original alarm.</li> |
| 156 | </ul> |
| 157 | |
Katie McCormick | 7bdb3f6 | 2013-09-05 14:46:20 -0700 | [diff] [blame] | 158 | |
| 159 | <h3 id="type">Choose an alarm type</h3> |
| 160 | |
| 161 | <p>One of the first considerations in using a repeating alarm is what its type should be.</p> |
| 162 | |
| 163 | |
| 164 | <p>There are two general clock types for alarms: "elapsed real time" and "real time clock" |
| 165 | (RTC). |
| 166 | Elapsed real time uses the "time since system boot" as a |
| 167 | reference, and real time clock uses UTC (wall clock) time. This means that |
| 168 | elapsed real time is suited to setting an alarm based on the passage of time (for |
| 169 | example, an alarm that fires every 30 seconds) since it isn't affected by |
| 170 | time zone/locale. The real time clock type is better suited for alarms that are dependent |
| 171 | on current locale.</p> |
| 172 | |
| 173 | <p>Both types have a "wakeup" version, which says to wake up the device's CPU if the |
| 174 | screen is off. This ensures that the alarm will fire at the scheduled time. This is useful |
| 175 | if your app has a time dependency—for example, if it has a limited window to perform a |
| 176 | particular operation. If you don't use the wakeup version of your alarm type, then |
| 177 | all the repeating alarms will fire when your device is next awake.</p> |
| 178 | |
| 179 | <p>If you simply need your alarm to fire at a particular interval (for example, every half |
| 180 | hour), use one of the elapsed real time types. In general, this is the better choice.</p> |
| 181 | |
| 182 | <p>If you need your alarm to fire at a particular time of day, |
| 183 | then choose one of the clock-based real time clock types. Note, however, that this approach can |
| 184 | have some drawbacks—the app may not translate well to other locales, and if the user |
Katie McCormick | 49f9348 | 2014-02-07 14:33:10 -0800 | [diff] [blame] | 185 | changes the device's time setting, it could cause unexpected behavior in your app. Using a |
| 186 | real time clock alarm type also does not scale well, as discussed above. We recommend |
| 187 | that you use a "elapsed real time" alarm if you can.</p> |
Katie McCormick | 7bdb3f6 | 2013-09-05 14:46:20 -0700 | [diff] [blame] | 188 | |
| 189 | <p>Here is the list of types:</p> |
| 190 | |
| 191 | <ul> |
| 192 | |
| 193 | <li>{@link android.app.AlarmManager#ELAPSED_REALTIME}—Fires the pending intent based |
| 194 | on the amount of time since the device was booted, but doesn't wake up the device. The |
| 195 | elapsed time includes any time during which the device was asleep.</li> |
| 196 | |
| 197 | <li>{@link android.app.AlarmManager#ELAPSED_REALTIME_WAKEUP}—Wakes up the device and |
| 198 | fires the pending intent after the specified length of time has elapsed since device |
| 199 | boot.</li> |
| 200 | |
| 201 | <li>{@link android.app.AlarmManager#RTC}—Fires the pending intent |
| 202 | at the specified time but does not wake up the device.</li> |
| 203 | |
| 204 | <li>{@link android.app.AlarmManager#RTC_WAKEUP}—Wakes up the |
| 205 | device to fire the pending intent at the specified time.</li> |
| 206 | </ul> |
| 207 | |
| 208 | <h4>ELAPSED_REALTIME_WAKEUP examples</h3> |
| 209 | |
| 210 | <p>Here are some examples of using {@link android.app.AlarmManager#ELAPSED_REALTIME_WAKEUP}. |
| 211 | </p> |
| 212 | |
| 213 | <p>Wake up the device to fire the alarm in 30 minutes, and every 30 minutes |
| 214 | after that:</p> |
| 215 | |
| 216 | <pre> |
| 217 | // Hopefully your alarm will have a lower frequency than this! |
| 218 | alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, |
| 219 | AlarmManager.INTERVAL_HALF_HOUR, |
| 220 | AlarmManager.INTERVAL_HALF_HOUR, alarmIntent);</pre> |
| 221 | |
| 222 | <p>Wake up the device to fire a one-time (non-repeating) alarm in one minute:</p> |
| 223 | |
| 224 | <pre>private AlarmManager alarmMgr; |
| 225 | private PendingIntent alarmIntent; |
| 226 | ... |
| 227 | alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); |
| 228 | Intent intent = new Intent(context, AlarmReceiver.class); |
| 229 | alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0); |
| 230 | |
| 231 | alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, |
| 232 | SystemClock.elapsedRealtime() + |
| 233 | 60 * 1000, alarmIntent);</pre> |
| 234 | |
| 235 | |
| 236 | <h4>RTC examples</h3> |
| 237 | |
| 238 | <p>Here are some examples of using {@link android.app.AlarmManager#RTC_WAKEUP}.</p> |
| 239 | |
| 240 | <p>Wake up the device to fire the alarm at approximately 2:00 p.m., and repeat once a day |
| 241 | at the same time:</p> |
| 242 | |
| 243 | <pre>// Set the alarm to start at approximately 2:00 p.m. |
| 244 | Calendar calendar = Calendar.getInstance(); |
| 245 | calendar.setTimeInMillis(System.currentTimeMillis()); |
| 246 | calendar.set(Calendar.HOUR_OF_DAY, 14); |
| 247 | |
| 248 | // With setInexactRepeating(), you have to use one of the AlarmManager interval |
| 249 | // constants--in this case, AlarmManager.INTERVAL_DAY. |
| 250 | alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), |
| 251 | AlarmManager.INTERVAL_DAY, alarmIntent);</pre> |
| 252 | |
| 253 | <p>Wake up the device to fire the alarm at precisely 8:30 a.m., and every 20 minutes |
| 254 | thereafter:</p> |
| 255 | |
| 256 | <pre>private AlarmManager alarmMgr; |
| 257 | private PendingIntent alarmIntent; |
| 258 | ... |
| 259 | alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); |
| 260 | Intent intent = new Intent(context, AlarmReceiver.class); |
| 261 | alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0); |
| 262 | |
| 263 | // Set the alarm to start at 8:30 a.m. |
| 264 | Calendar calendar = Calendar.getInstance(); |
| 265 | calendar.setTimeInMillis(System.currentTimeMillis()); |
| 266 | calendar.set(Calendar.HOUR_OF_DAY, 8); |
| 267 | calendar.set(Calendar.MINUTE, 30); |
| 268 | |
| 269 | // setRepeating() lets you specify a precise custom interval--in this case, |
| 270 | // 20 minutes. |
| 271 | alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), |
| 272 | 1000 * 60 * 20, alarmIntent);</pre> |
| 273 | |
| 274 | <h3>Decide how precise your alarm needs to be</h3> |
| 275 | |
| 276 | <p>As described above, choosing the alarm type is often the first step in creating an alarm. |
| 277 | A further distinction is how precise you need your alarm to be. For most apps, |
| 278 | {@link android.app.AlarmManager#setInexactRepeating setInexactRepeating()} is the right |
| 279 | choice. |
| 280 | When you use this method, Android synchronizes multiple inexact repeating alarms and fires |
| 281 | them at the same time. This reduces the drain on the battery.</p> |
| 282 | |
| 283 | <p>For the rare app that has rigid time requirements—for example, the alarm needs to |
| 284 | fire precisely at 8:30 a.m., and every hour on the hour |
| 285 | thereafter—use {@link android.app.AlarmManager#setRepeating setRepeating()}. But you |
| 286 | should avoid using exact alarms if possible.</p> |
| 287 | |
| 288 | <p>With {@link android.app.AlarmManager#setInexactRepeating setInexactRepeating()}, |
| 289 | you can't specify a custom interval the way you can with |
| 290 | {@link android.app.AlarmManager#setRepeating setRepeating()}. You have to use one of the |
| 291 | interval constants, such as {@link android.app.AlarmManager#INTERVAL_FIFTEEN_MINUTES}, |
| 292 | {@link android.app.AlarmManager#INTERVAL_DAY}, and so on. See {@link android.app.AlarmManager} |
| 293 | for the complete list. |
| 294 | </p> |
| 295 | |
| 296 | <h2 id="cancel">Cancel an Alarm</h2> |
| 297 | |
| 298 | <p>Depending on your app, you may want to include the ability to cancel the alarm. |
| 299 | To cancel an alarm, call {@link android.app.AlarmManager#cancel cancel()} on the Alarm |
| 300 | Manager, passing in the {@link android.app.PendingIntent} you no longer want to fire. For |
| 301 | example:</p> |
| 302 | |
| 303 | <pre>// If the alarm has been set, cancel it. |
| 304 | if (alarmMgr!= null) { |
| 305 | alarmMgr.cancel(alarmIntent); |
| 306 | }</pre> |
| 307 | |
| 308 | <h2 id="boot">Start an Alarm When the Device Boots</h2> |
| 309 | |
| 310 | <p>By default, all alarms are canceled when a device shuts down. |
| 311 | To prevent this from happening, you can design your application |
| 312 | to automatically restart a repeating alarm if the user reboots the device. This ensures |
| 313 | that the {@link android.app.AlarmManager} will continue doing its task without the user |
| 314 | needing to manually restart the alarm.</p> |
| 315 | |
| 316 | |
| 317 | <p>Here are the steps:</p> |
| 318 | <ol> |
| 319 | <li>Set the <a href="{@docRoot}reference/android/Manifest.permission.html#RECEIVE_BOOT_COMPLETED"> |
| 320 | {@code RECEIVE_BOOT_COMPLETED}</a> permission in your application's manifest. This allows |
| 321 | your app to receive the |
| 322 | {@link android.content.Intent#ACTION_BOOT_COMPLETED} that is broadcast after the system |
| 323 | finishes booting (this only works if the app has already been launched by the user at least once): |
| 324 | <pre> |
| 325 | <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/></pre> |
| 326 | </li> |
| 327 | |
| 328 | <li>Implement a {@link android.content.BroadcastReceiver} to receive the broadcast: |
| 329 | <pre>public class SampleBootReceiver extends BroadcastReceiver { |
| 330 | |
| 331 | @Override |
| 332 | public void onReceive(Context context, Intent intent) { |
| 333 | if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) { |
| 334 | // Set the alarm here. |
| 335 | } |
| 336 | } |
| 337 | }</pre></li> |
| 338 | |
| 339 | <li>Add the receiver to your app's manifest file with an intent filter that filters on |
| 340 | the {@link android.content.Intent#ACTION_BOOT_COMPLETED} action: |
| 341 | |
| 342 | <pre><receiver android:name=".SampleBootReceiver" |
| 343 | android:enabled="false"> |
| 344 | <intent-filter> |
| 345 | <action android:name="android.intent.action.BOOT_COMPLETED"></action> |
| 346 | </intent-filter> |
| 347 | </receiver></pre> |
| 348 | |
| 349 | |
| 350 | <p>Notice that in the manifest, the boot receiver is set to |
| 351 | {@code android:enabled="false"}. This means that the receiver will not be called |
| 352 | unless the application explicitly enables it. This prevents the boot receiver from being |
| 353 | called unnecessarily. You can enable a receiver (for example, if the user sets an alarm) |
| 354 | as follows:</p> |
| 355 | |
| 356 | <pre>ComponentName receiver = new ComponentName(context, SampleBootReceiver.class); |
| 357 | PackageManager pm = context.getPackageManager(); |
| 358 | |
| 359 | pm.setComponentEnabledSetting(receiver, |
| 360 | PackageManager.COMPONENT_ENABLED_STATE_ENABLED, |
| 361 | PackageManager.DONT_KILL_APP); |
| 362 | </pre> |
| 363 | |
| 364 | <p>Once you enable the receiver this way, it will stay enabled, even if the user reboots |
| 365 | the device. In other words, programmatically enabling the receiver overrides the |
| 366 | manifest setting, even across reboots. The receiver will stay enabled until your app disables it. |
| 367 | You can disable a receiver (for example, if the user cancels an alarm) as follows:</p> |
| 368 | |
| 369 | <pre>ComponentName receiver = new ComponentName(context, SampleBootReceiver.class); |
| 370 | PackageManager pm = context.getPackageManager(); |
| 371 | |
| 372 | pm.setComponentEnabledSetting(receiver, |
| 373 | PackageManager.COMPONENT_ENABLED_STATE_DISABLED, |
| 374 | PackageManager.DONT_KILL_APP);</pre> |
| 375 | |
| 376 | </li> |
| 377 | </ol> |