Sleeping service with contentobserver - android

I've created a service (S) which hosts a ContentObserver (C).
C keeps track of some data and logs changes made to a database (D).
S also has a timer which dumps the content of D to a file on timed intervals.
I have my service running on my phone and all seems fine for a while (a couple of hours or so). Then suddenly it stops recording changes made to the data and stops dumping to a file.
I tried changing the data (provoking onChange on C) and browsing around in the phone to keep the device awake but nothing happened - service stil inactive.
S is still running and when I connect to my laptop I see no errors in the log.
My guess is that the service is sleeping (gets no CPU slice). I've read a bit about a wakelock but I don't want to force the phone to be awake all the time. ().
An alternative is to create a repeated alarm which carry out the work of C every T minutes (polling).
I like the idea with ContentObservers more because the user can alter (especially delete) data between the updates. With a ContentObserver I will get ALL changes, not just snapshots in timed intervals.
Any ideas on how I can wake my service on a regularbasis?
Best regards
Frederik

You can use the AlarmManager to broadcast a pending intent at a set interval. If you use the RTC_WAKEUP type, it will even get sent if the device is asleep.
Intent intent = new Intent("android.intent.action.DO_SOMETHING");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(Service.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 60*60*1000, pendingIntent);
Then simply register a broadcast receiver for the intent and do what you must do.
Note that broadcast receivers timeout after aprox. 10 sec, so if you got a long task, use a service

Related

Does AlarmManager require the PendingIntent to be of Type BroadcastReceiver?

The documentation for AlarmManager seems to imply (but does not outright explicitly require) that the PendingIntent you pass in to any of the set() methods should be of the type BroadcastReceiver, but I tested passing in other component types (like an IntentService) and it seemed to work fine.
Is it safe to use non-BroadcastReceiver Intents with AlarmManager?
Yes, and it has always worked, but I suspect not in the way that you're thinking. You can use any PendingIntent with an alarm; this could indeed be an activity or service PendingIntent. If it's a service PendingIntent, then the OS will call startService() for you when the alarm fires. The hidden catch is about the behavior of wakeup alarms.
When any alarm fires, the OS holds a wakelock on the sender's behalf for as long as it takes to deliver the PendingIntent, at which point the wakelock is released and the device is allowed to go back to sleep. The exact meaning of "as long as it takes to deliver" depends on which kind of PendingIntent is being used.
Broadcast delivery is essentially treated as synchronous: the wakelock is held by the Alarm Manager until the recipient's onReceive() callback returns. This gives you a hard guarantee that whatever processing you want to do in onReceive() is guaranteed to proceed without the device sleeping.
However, activity and service PendingIntent delivery does not wait for the recipient in the same way. With those kinds of alarm PendingIntents, the device remains awake long enough to begin the process of starting the target activity or service, but then it can (and does) go back to sleep immediately after that launch has begun, before the target code actually has a chance to run. In practice this means that with a service PendingIntent, even if the alarm is a wakeup alarm, the service will often not actually execute until the device as a whole is woken up normally, e.g. the next time the user turns on the screen manually.
Sometimes this is okay, if your code doesn't actually care that even though the alarm fired at 3am, the service didn't start running until 7am when the alarm clock went off and lit up the phone for an extended period. More often, though, what apps need to do is use a broadcast alarm, then in their onReceive() -- knowing that the device will sleep as soon as they return -- acquire their own wakelock and start up the service under that wakelock, etc.
There is a terrific support library class called WakefulBroadcastReceiver that encapsulates this alarm-wakelock-service dance and makes it both easy and bulletproof; it's https://developer.android.com/reference/android/support/v4/content/WakefulBroadcastReceiver.html. Use that if you ever want to start a service in response to a wakeup alarm.

Android does not execute everything on night

I made a program that creates a Service.
The service connects to a website every 5 minutes, collects one line of data and outputs it to a file.
My problem is that it didn't collect the data every 5 minutes. The data was collected once in around 50-70min. Why? Is there something in android that prevents background services from running properly during nights? What is also strange to me, the 50-70 minute breaks happened only when I was not using my phone.
Times it collected the data:
1:40
1:45
1:50
1:55
2:00
2:05
2:10
2:15
2:20
2:25
2:30 I was awake until this.
3:20
4:15
5:00
6:05
6:55
7:55
8:45
10:20
10:50 Woke up at here.
10:55
Your results are not surprising. Android was designed to swipe out (and back in) processes based overall level of resource as well as other factors.
Modifying your service to become a foreground service will certainly improve your results:
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);
Foreground services are basically services guaranteed by Android to be less susceptible to swipe out,
which is what you want.
But even a foreground service will halt its processing when the devices goes to sleep. And, if you feel your polling logic is important enough so to keep the device from sleeping, you should also acquire a wakelock.
Note: Long running wakelocks have a huge impact of on battery usage. Handle with care!
Finally, please consider using an alarm for your task. Alarms are usually considered better option for
long running polling tasks.
Depending of an approach you use to schedule your updates, the OS might shift updates to decrease battery drain and overall burden. Delayed tasks might be postponed if the device falls into deep sleep (happens at night mostly as the device is inactive during long periods of time).
It's done this way to prevent your battery to be drained to fast. If you really want to wake your device every 5 minutes, you can check the answer to this post and use the AlarmManager

Android AlarmManager incomprehensible behavior

i know AlarmManager was discussed several times, but i really can't find an answer that can help me. I have an app which needs to start a service at a certain time and make some stuff, so after some research work, i decided that AlarmManager is what i need.
I use this code to do the job
Intent myIntent=new Intent();
ComponentName cn=new ComponentName("my.package.name", "my.package.name.AlarmService");
myIntent.setComponent(cn);
PendingIntent pendingIntent= PendingIntent.getService(alarm._context, alarm.id, myIntent, 0);
AlarmManager alarmManager = (AlarmManager) _context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, alarm.time, pendingIntent);
Where "alarm" is an object written by me.
Now, i am sure like the death that this code works, because if i set one (or more) action for 2 minutes or hours forward, it works (i write a log on file in the first instruction of the service). If i execute
adb shell dumpsys alarm
I can see all of my pending intents.Ok, happy to see everything working, i schedule my actions at:
01:00 AM
08:00 AM
08:40 AM
09:15:AM
01:00 PM
02:00 PM
18:00 PM
after setting this actions, i execute
adb shell dumpsys alarm
and i can see all of the pending intents. Then i go to sleep and..... when i wake up in the morning at 07:30 AM, the action scheduled at 01:00 AM has not been executed and if i execute
adb shell dumpsys alarm
all of my pending intents are disappeared!!!!!!!
I am really frustrated of this behavior, because i spent a lot of time writing this application and i can't get it working properly. I'm posting this question after weeks of researchs, because i tryed every thing, but i still have this problem. Please help me
From the docs for AlarmManager (link here):
The Alarm Manager holds a CPU wake lock as long as the alarm
receiver's onReceive() method is executing. This guarantees that the
phone will not sleep until you have finished handling the broadcast.
Once onReceive() returns, the Alarm Manager releases this wake lock.
This means that the phone will in some cases sleep as soon as your
onReceive() method completes. If your alarm receiver called
Context.startService(), it is possible that the phone will sleep
before the requested service is launched. To prevent this, your
BroadcastReceiver and Service will need to implement a separate wake
lock policy to ensure that the phone continues running until the
service becomes available.
If your Service does not also hold set up proper wake locks, the device will go right back to sleep when the AlarmManager is finished, you need to manage this as well in your code.
HTH

Keeping a GPS service alive and optimizing battery life

I must build an application with a GPS tracker running during about a day. I'm aware of similar questions in SO but I haven't found any answers to some questions I have.
-I need a GPS fix every 10 min, so I think the best way to do it is to start the location service, get a fix (or timeout) and stop the service (with removeUpdates()). How can I have an application (or service or whatever) running this cycle every 10min and be sure it will continue as long as there is some battery left (even if device goes to sleep, it should wake it up every 10min to get a fix)? Is using AlarmManager a good idea?
-Can I expect the battery to last one day with this method?
I've checked mytracks but the gps listener seems always on and the battery is expected to last no more than 5h.
I've also checked CWAC Location Poller but it does only removeUpdates() on timeout and restart the listener immediately. It also uses a wakelock while in my case I think an AlarmManager could be a better idea.
Any help/suggestion welcome
You are spot on with alarm manager I use
Intent serviceIntent = new Intent(this, TrackerService.class);
mPendingIntent = PendingIntent.getService(this, 0, serviceIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.cancel(mPendingIntent);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(), interval, mPendingIntent);
in a similar app for getting network location
interval is ms between starting the service
the service starts up, gets the location and closes
this was MUCH more battery efficient that hanging around with an active service waiting for reports
that code i posted cancels the previous alarms first so you don't get more than 1 :)
You can check out Passive Receiver
It'll give you an location update whenever another the devices location gets updated - only works on 2.2 or later

How to keep a task alive after phone sleeps?

my application needs to send a message to my server every 30 seconds or so.
I understand I need to use AlarmManager using RTC_WAKEUP or ELAPSED_REALTIME_WAKEUP.
now I don't understand two things:
1) If the AlarmManager wakes up the device, why do I need to aquire a WakeLock?
2) I saw an example for using AlarmManager with WakeLock. In this example, its setting the alarm to send a broadcast to a broadcast receiver which then acquires a static wake lock and then start an IntentService which runs a task.
now, my question is, in my case, I need to follow this example entirely? why don't set the alarm to start a service instead?

Categories

Resources