Is there an easier way to use AlarmManager or to set real-time based alarms?
Asked Answered
E

1

0

It seems that the only way to time actions based on the actual elapsed time (as opposed to uptime, which stops when the device sleeps) is the AlarmManager.

Is there an an easy way to do "wallclock"-based delayed exectuion, for example through an open-source wrapper around AlarmManager?

For normal timing operations, you can use a handler, which is as easy as such a simple task should be:

  • Implement the handler callback (no registration necessary)
  • Instantiate a Handler
  • Call sendEmptyMessageDelayed or similar functions
  • To clean up all your set delays, just call removeCallbacksAndMessages(null)

However, Handler only supports uptime-based delays, which sometimes are not sufficient (e.g. if you want to check the server for new messages every 15 minutes).

If you want those, it seems that you have to use the AlarmManager, which is not very comfortable:

  • Define an action for your alarm
  • Create a receiver (either by creating a dedicated receiver class and declaring it the manifest, or implementing the interface, registering the receiver using registerReciever, and unregistering it when done)
  • Create an intent for your action
  • Wrap said intent in a pending intent, and store the pending intent if you want to cancel the alarm
  • Fetch an alarm manager (this requires a context)
  • Set the alarm
  • When you want to cancel the alarm, cancel it using the stored pendingIntent
  • Should you decide to have multiple intents or intents with changing data, you will have to save them all to clean up the alarm manager afterwards
Essequibo answered 25/4, 2013 at 8:56 Comment(0)
G
0

For normal timing operations, you can use a handler

Only from a foreground activity. Any other use of Handler for long-term polling is unreliable at best, even ignoring your concerns regarding uptime calculations.

Define an action for your alarm

This is not necessary. It is not even a good idea.

Create a receiver (either by creating a dedicated receiver class and declaring it the manifest, or implementing the interface, registering the receiver using registerReciever, and unregistering it when done)

If you want the event to occur when you are not in the foreground and the alarm to go off while the device is asleep (_WAKEUP alarms), the manifest-registered receiver is required. If _WAKEUP is not needed, a service will suffice. If you only need to be in the foreground and receive the event in an activity, use createPendingResult() to give you a PendingIntent that will trigger onActivityResult() of your activity. Though, in this latter case, it would make more sense to use postDelayed() on a View or Handler.

and store the pending intent if you want to cancel the alarm

If storing a PendingIntent is an option, then Handler is all you need, and AlarmManager is unsuitable. To cancel an alarm, you need an equivalent PendingIntent (one where the underlying Intent objects match based on filterEquals() and where the PendingIntent operation [activity, service, broadcast] is the same).

When you want to cancel the alarm, cancel it using the stored pendingIntent

No, you cancel it by creating an equivalent PendingIntent.

Should you decide to have multiple intents or intents with changing data, you will have to save them all to clean up the alarm manager afterwards

No, you cancel them by creating an equivalent PendingIntent.

Is there an an easy way to do "wallclock"-based delayed exectuion, for example through an open-source wrapper around AlarmManager?

Creating wrapper code for this that covers 80% of the work would have taken you less time than it did to write your question. I am not aware of a dedicated library for this, partly because there wouldn't be all that much to it.

Or, use ScheduledExecutorService and a WakeLock, for short-term things. This is unsuitable for "every 15 minutes" scenarios, as it keeps the device awake all of the time.

Grays answered 25/4, 2013 at 12:5 Comment(6)
I have a long-running service that is constantly running (startForeground) and collects/exchanges data, but does not hold a wake lock all the time. I want it to upload logs every X minutes. postDelayed would upload it every X minutes of uptime (i.e. if the device slept a lot, maybe once a day). I prefer using existing wrappers because they are usually tested quite a bit and cover things that are easily forgotten. By define an action, I meant a constant with an action name, not something in the manifest. Is there some kind of "catch-all" action that should be used instead?Essequibo
@JanSchejbal: "I have a long-running service that is constantly running (startForeground)" -- that is rarely in the user's best interest. "Is there some kind of "catch-all" action that should be used instead?" -- use no action at all. Use an explicit Intent (new Intent(this, MyBroadcastReceiver.class)).Grays
It is a data collection app running a P2P network via Bluetooth - it needs to listen for incoming connections nonstop. Luckily in practice, Bluetooth does wake up the device, so I don't need a permanent wakelock. /// I register my receiver instances with registerReceiver, and I believe that I have to specify a filter and use an action for that - am I mistaken? I want a specific instance to handle the "Broadcast", not a fresh one that is spawned every time. (I only use intents because there seems to be no other way to get wallclock timeouts, I'd rather avoid them alltogether.)Essequibo
@JanSchejbal: "Luckily in practice, Bluetooth does wake up the device" -- I would not assume that behavior across all devices. If this is targeting some hardware that you control, that's fine. "I register my receiver instances with registerReceiver, and I believe that I have to specify a filter and use an action for that - am I mistaken?" -- yes, in that case, you would.Grays
re. wakeup -- I know it's risky, but all hardware I tested does it, and finding out if any doesn't will be part of the larger tests. Wakelocks are just too expensive to use preventively. /// "yes, in that case, you would" -- be mistaken or need an action? Thanks for all the help!Essequibo
@JanSchejbal: Yes, in that case, you would need an action.Grays

© 2022 - 2024 — McMap. All rights reserved.