Using AlarmManager to update widgets manually - android

As stated in the Android Dev Guide, if you want a widget to update more often you should use the AlarmManager to set alarms that do not wake the device.
In principle: do not use the standard mechanisms provided by the AppWidgetProvider class and its easy set up with android:updatePeriodMillis in the xml file.
I am sorry to ask, but the guide just states "use AlarmManager, use RTC or ELAPSED_REALTIME, ..." but HOW EXACTLY do I send an intent to just update my widget is missing!!!
Could anybody please state the code I need to form the PendingIntent that mimics the default behaviour? I don't have a clue how to get the widget ids, which action I should use and so on... Sad the dev guide stops explaining at that point!
What is needed as extras to which action?
In case somebody is interested why I want to update more frequently than 30 minutes: my widget shows when the next bus departs at a station. There is a bus every 20 minutes, so I got two options: update the widget every minute, displaying the departure time of the next bus (that's what I want!!) or, not that good, state the departure time of the next bus so I will have to update at least every 20 minutes!
Now: when the device is asleep, of course, this should never wake it up - so my understanding of this section in the dev guide is that this is the correct way to implement it; anybody thinks I'm wrong?
Oh, another thing I would like to find out: if the device is asleep when the widget should be updated and my alarm is not issued due to the sleeping device, will it be updated IMMEDIATELY when it wakes up???
Thanks for your help!!
PS: I really wonder why the xml definition of a widget provider does not allow to simply state "don't wake the device" by a boolean switch... that would make life so much easier in the first place! What kind of a widget needs to wake device anyhow??? ;-)
This is how far I came up to now, but it does not work - nothing happens:
private void startAlarm(Context pContext) {
Log.d(TAG, "startAlarm");
AlarmManager am = (AlarmManager) pContext.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent("android.appwidget.action.APPWIDGET_UPDATE");
intent.setClass(pContext, getClass());
PendingIntent pi = PendingIntent.getBroadcast(pContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
am.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + 1000, pi);
}

Could anybody please state the code I need to form the PendingIntent that mimics the default behaviour?
I wouldn't, because AFAIK it is not possible to "mimic the default behavior" precisely. Simply have the AlarmManager alarm use a PendingIntent that either sends a custom action to your AppWidgetProvider that you process in onReceive(), or calls startService() on the IntentService you are using for the real smarts behind your app widget.
I don't have a clue how to get the widget ids
You saved the widget IDs from actual onUpdate() calls, such as when the app widget is first put on the screen. When your alarm goes off, update all your app widgets.
update the widget every minute, displaying the departure time of the next bus (that's what I want!!)
Please allow this to be user-configurable.
Oh, another thing I would like to find out: if the device is asleep when the widget should be updated and my alarm is not issued due to the sleeping device, will it be updated IMMEDIATELY when it wakes up???
AFAIK, yes, but I have not used alarms that are not of the _WAKEUP variety.

Don't know if they can still help you but I wrote some posts about Android Widget some days ago.
Here is the one regarding the AlarmManager:
http://malubu.wordpress.com/2012/06/05/take-your-time-widgets-and-alarmmanager/

Related

Android background Services, Alarms and preserving object reference after application restart

I'm developing a little Android app, that needs to run a background process, used to start a remote connection periodically (for example, to check if there is new data on the server). This process obviously needs to work also if the application activity is not running at the moment.
As I can see in documentation, there are two types of approach to develop a scheduled background process in Android, working also when the application is closed.
Services
Alarms
The first one is not so good for my requirementes, because it can be killed by OS in case of low memory, so it is useless for me. startForeground() is not so good because I want the process is silent.
Alarm is ok, because it can't be killed by the OS, so it can work indefinitely. But... If I schedule an Intent with the AlarmManager, how can I preserve a reference to the Intent, surviving at application restart?
For example, if I want to cancel, or reschedule the Alarm, I need the reference to the initial Intent to cancel it thorugh the "AlarmManager.cancel(Intent i)" method. But if the application was restarted by the user, how can I obtain a reference to the initial Intent that was used to start the alarm?
Is there another way to stop an alarm if the launching application was restarted?
about alarms, you can cancel using the intent characteristics, so you don't need a reference to the original intent. In any case, the alarms mechanism still need you to run something on a service.
In any case, you missed another possible solution: SyncAdapter. Its purpose is to sync with servers, but you can do whatever you wish in the code, and it's unlikely the OS will kill it, as opposed to the other solutions you've mentioned.
Sadly even now it lacks on documentation and samples, but I think it can fulfill your needs. Here's what I've found
yes, note that cancel is looking for a PendingIntent, not an Intent per se.
so
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, R.string.some_string, new Intent(this, InitialIntent.class), 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
gets you where you want to be.
note that I'm not getString'ing that string, that's becasue I want a unique Id/request code for this intent that I'm not going to screw up copypasting; I reference the same number when creating the alarm in InititalIntent.
This question was just answered, here:
How can I get the context of other activity?
Just cancel the intent you scheduled
Your best bet would be to make use to push notification (via GCM), whenever something new is available on the server. I am working on similar application where data can be pushed from one side (producers) and needs to be pushed to the consumer apps.
You need to look at BroadcastReceiver and GCM specific communication model. Hope this helps

Android, set custom timing of AlarmManager... Please advise

Hi I need to set AlarmManager to run a reminder for me to take medication. I need to repeat it by custom amount of days and custom amount of times to take in the day.
So is there an efficient way to set the AlarmManager or CommonsWare's Implementation of the AlarmManager to remind me "twice a day starting at 9AM for the next 5 days" to remind me to take medication? Pls advice and tnx in advance for any constructive help in sample code and in relevant tutorials.
I haven't looked into Mark's AlarmManager implementation, but there is no way, in general, to get the bare AlarmManager to do what you are trying to do. You can schedule a single alarm, at a specific time, or a repeating alarm, that repeats at fixed intervals. If you want something that handles complex schedules like the one you describe, you'll have to write or find code that does it.
You want to use a PendingIntent with the AlarmManager. The idea is to schedule the pendingIntent with the alarmManager, have that trigger an intentService or broadcast, setup another pendingIntent with the alarmManager for the next desired event. You want to keep in mind that you'll need the BOOT_RECEIVED permission in case the user reboots their device. I have complex scheduling in Audio Control and this is exactly what I do.
Here is a pretty decent tutorial of what I mean:
http://android-er.blogspot.com/2010/10/simple-example-of-alarm-service-using.html
You need to schedule an alarm to the next time you want to take the medicine - according to your algorithm (for example if its twice a day, and you got to the pending intent callback for the first time today, then schedule the next alarm to start after [6,7,8,9,10...] hours).
You will need to save both last time of the alarm launch and the user settings in shared prefs/file/DB.
You need to handle process down (android killed it or the device was rebooted). In the case of device reboot you should use the boot receiver to start your service, but you need to remember that from android 3.1 the user has to use at least one time the GUI in order for you to intercept the boot completed receiver. The boot completed receiver should look when was the last time that the alarm launched, and according to the user settings set the next alarm launch.
In the case of android killed your service, you will need to make research, i can't help here.
see example

Scheduling background work in Android

I'm new to Android so I want to make sure that the following solution is the correct one.
The problem:
I want to sync the device's local database with a database on my server, via a webservice, every 10 minutes. I already have a web service call that I can make that returns the new/updated records. What I'm wondering is what is the best way to schedule this task. I want the databases to sync even when the application is not running.
My solution (is this the correct route to go?):
I will have one BroadcastReceiver that listens for android.intent.action.BOOT_COMPLETED, in it's onReceive I will create an AlarmManager that sends a message to MyReceiver (via a PendingIntent) every 10 minutes. Also, in my application's startup I will do the same (create an alarm to send messages to the MyReceiver via a PendingIntent) - Since both alarms are sending messages to MyReceiver and their corresponding PendingIntents are initialized with PendingIntent.FLAG_UPDATE_CURRENT will the new alarm override the old one? (this is what I want to do, in case for some reason the alarm gets cancelled after device boot it should be restarted when the application starts).
In MyReceiver's onReceive() I will create a MyIntentService (this instance will make the webservice call and update the local database).
Is this a good solution? Any suggestions?
Thanks
Solution is fine...Actually all the AlarmManager instances get cleared when device turned off and rebooted.
The simple way is that...
First create AlarmManager when application started.
Second in onReceive of BOOT_COMPLETED BroadcastReceiver.
Its enough, PendingIntent.FLAG_UPDATE_CURRENT will make sure of having only one activated alarm at a time.
In this way, alarm registered when your application started. There will be no issue if its already registered via BOOT_COMPLETED. Activated alarm will deactivated when you turn off your device, but BroadcastReceiver to BOOT_COMPLETED will take care of registration new alarm at next boot.
If you decide that this answers your question, please mark it as "accepted". This will raise both your and my reputation score.
Also you need to review your interval to use network, it might be very resource consuming for device and user. One policy might be to have longer period of interval and check for update when user starts your app (this might not be user friendly but can save many system resources and battery power as well). Try to find some better policy according to your needs.
Using FLAG_UPDATE_CURRENT in that manner will override the existing PendingIntent if one exists. I'm not positive but I believe that as soon as you get into onReceive, the PendingIntent is consumed so it's no longer there to be overridden. In either case, it sounds like this is the functionality you are looking for and yes it's a good way to solve this kind of problem. My only other suggestion would be if the 10 minute interval timing is not absolutely critical then use one of the INTERVAL_ schedules (INTERVAL_FIFTEEN_MINUTES for example) in your AlarmManager to help conserve battery life; basically it lets allows all apps that run on intervals to "batch" their work together and wake the device up less frequently.

AlarmService onBoot with interval based on variable

Alright so I'm working on a project where I want the app to check the internet for updates. I also want the user to be able to customize how often it makes these checks.
I'm kinda struggling with how I go about doing this.
I'm thinking I have a BroadcastReceiver check for the Intent.ACTION_BOOT_COMPLETED, and then start the AlarmService based upon a variable already set somewhere.
But what happens if the user wants to update the interval? How do I stop the old AlarmService and replace it with the new one?
Also how do I have my AlarmService run a "background update" portion in my app without actually running any of the activities?
EDIT: Also can someone advise if I'm using the AlarmService correctly? I'd want to check for updates fairly frequently, should I be using some other method? I'd check between 1-5 minutes.
I do a similar thing in my app. I basically have two services: one that sets the alarm and the other that does the actual donwloading.
When your BroadcastReceiver get's the intent ACTION_BOOT_COMPLETED you start your alarmService which sends an broadcast to start the downloadService.
So your BroadcastReceiver does both things: starts the alarmServcie if intent == BOOT_COMPLETED else it starts the downloadservice.
Also if the user changes the periods in which he wants those updates to be done you store the chosen value in the preferences, start the alarmservice and retrieve the values to set up a new period, e. g. 1 hour, 2 hours
Edit: Here is the info some info from the docs about pending Intents and how to cancel them. http://developer.android.com/reference/android/app/PendingIntent.html
When the user changes the interval you should first cancel your old alarmservice and then set it again.

Best moment/location for setting an AlarmManager

My application shows content for a site that also has a notification system. I want to show if there are new notifications, and I am using an AlarmManager that calls an IntentService.
My question is: where should I start/register this AlarmManager? I've put it in the onCreate() of my activity just for proof-of-concept (and its working fine, thank you very much :) ), but if you would start that activity twice, you would get multiple alarms.
The only possible solution I've come up with is this, but I don't know if this would be best practice
Start the manager in an onCreate() if the preference "alarm started" is false
Set some variable that it is started in preferences.
Now if the alarm stops for some reason, there's no way to restart it. So, a variation would be:
Always call cancel in the onCreate()
And then always set the Alarm.
This seems like a common pattern: Wanting to periodically get information with an alarm, and not setting that alarm more then once. How should I do this? When, where and how to register the alarm?
Also, continueing on #Zelimir 's comment: can you check if a certain alarm is allready set?
Ideally, the alarm would be set regardless of the activity being started or not of course, but that might be another thing.
For completeness, this is the code I'm currently using to start the alarm:
AlarmManager alMan = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(this, CommentService.class);
PendingIntent penInt = PendingIntent.getService(this, 0, i, 0);
alMan.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(),
AlarmManager.INTERVAL_FIFTEEN_MINUTES,
penInt);
For even more completeness, the app description / situation.
The app is basically showing blogs (journals if you will) from a certain page. It has activities for adding entry, viewing entries, adding comments, etc. On the 'mother' site there is an option to recieve notifications (like the number you see here on SO too when you get a message). I want to show if there are new messages, and so retrieve them every xx minutes. It would be shown in the notificationbar for now, but it might feed some sort of widget later.
If you need more info: the app is called Androblip and it supports a site called blipfoto.com
When, where and how to register the alarm?
That is impossible to answer in the abstract. It depends entirely upon what the business rules are for your app, which you declined to supply in your question.
If the monitoring is to be happening all the time, a typical pattern is to register the alarm:
in onCreate() of your main activity for the very first run of your app
in a BOOT_COMPLETED BroadcastReceiver, to handle reboots, which wipe the AlarmManager roster
can you check if a certain alarm is allready set?
No, but you can cancel it without issue. Just create an equivalent PendingIntent and call cancel() on the AlarmManager.

Categories

Resources