Broadcast receiver vs activity with alarmmanager - android

I am using broadcast receiver with AlarmManager, but sometimes it takes lot of seconds to wake up, which causes issue in app functionality
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
wl.acquire();
and releases after launching activity
I am thinking to change it.
Can you tell what is the best approach?
use broadcast receiver to perform some calculations, and then starts activity (wake lock problem so far in my case).
Start Activity directly, and do calculations weather to continue this activity or terminate before setting content view

I am using broadcast receiver with AlarmManager, but sometimes it takes lot of seconds to wake up, which causes issue in app functionality
I am not aware that any other sort of component will somehow start up faster than a BroadcastReceiver. Certainly I would expect an activity to start up more slowly than does a BroadcastReceiver.
and releases after launching activity
The WakeLock is doing you no good, as there already is a WakeLock in place for the duration of your onReceive() call (assuming that this is a manifest-registered BroadcastReceiver).
The only way this WakeLock will be useful is if you release it from onCreate() of the activity, to try to keep the device awake long enough for the activity to start up.
Can you tell what is the best approach?
That depends on what the "calculations" are. onReceive() is called on the main application thread. Like all methods called on the main application thread, you want onReceive() to return in a couple of milliseconds. If your "calculations" will definitely take only a couple of milliseconds, stick with the BroadcastReceiver. If the "calculations" will take longer than that, you will want to consider delegating that work to an IntentService, and have the IntentService start the activity if needed.
With respect to the "lot of seconds", bear in mind that your AlarmManager events may be inexact, depending on what method you use to set them up, what your targetSdkVersion is, and what version of Android you are running on.

Related

Aquire partial wakelock in a IntentService

My IntentService gets fired from 2 places, either by an Alarm or by the Activity and since the duration is related to the amount of data it needs do fetch from the web, from what I understood, I need to keep a partial wakelock.
Here's my implementation:
#Override
protected void onHandleIntent(Intent intent) {
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WakeLock");
try {
wakeLock.setReferenceCounted(false);
wakeLock.acquire(3600000);
///other code here
}
catch{
}
finally{
if (wakeLock.isHeld()) {
wakeLock.release();
}
}
My question is: will this work good enough? Will the finally make sure that the wakelock is released in any circumstances? From what I know onHandleIntent handles intent one after another, so there is no risk in having 2 intents/2 wakelocks in the same time.
Later edit:
The IntentService is called in 2 ways:
from my Activity, like
startService(new Intent(context, MyService.class).putExtra()..);
2 from a triggered Alarm using a PendingIntent
PendingIntent pendingIntent = PendingIntent.getService(context, someId, myServiceIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Will the service have enough time to aquire wakelock when ran from the Alarm?
Whether you need to keep wake-lock or not should not be related to the amount of work your Service does - theoretically, device can go to sleep even if the amount of work is small.
Wake-locks should be considered only if you absolutely must ensure that device can't sleep while the Service is running. Cases like this are very rare. Some examples:
Alarm clock applications (need to wake you up even if the device is sleeping)
Real time messaging applications (need to notify you about new messages even if the device is sleeping)
Most applications don't have such a strict timing requirements. For example, the following are NOT good reasons to use wake locks:
Periodic synchronization of data with the server (should be delayed until device awakes)
Displaying current user's location on map (can be obtained when device awakens; but wake-lock will be needed for applications that monitor user's entire route)
If you really need to ensure that the device doesn't sleep during Service execution, then you need to acquire a wake-lock (one of the several types). Let's assume that this is the case here.
You want to be able to start the "wakeful" Service from application's UI (Activity), and using AlarmManager.
Starting from UI
Since the device should be completely awake in order for the user to interact with UI, you can safely assume that if you start the Service in response to UI interaction it will have a chance to acquire a wake-lock (but do it as soon as the Service is started).
Your solution covers this case.
Starting from AlarmManager
Unfortunately, there is no guarantee (at least no documented guarantee) that when AlarmManager starts the Service it will hold a wake lock and allow the Service to acquire its own wake-lock. This means that the device can go to sleep after alarm fired, but before your Service had a chance to acquire the wake-lock.
This means that your solution will "break" in this case.
The only documented scheme in which AlarmManager will help you with wake-locks involves broadcasts:
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.
This is where WakefulBroadcastReceiver comes in very handy.
Note that if you use this scheme, then there is no need to support a different one for "UI initiated" case - use the same approach in both cases.
You might also want to take a look at this library developed by #CommonsWare (I didn't use it myself though).

Need wake lock in IntentService : why go via WakefulBroadcastReceiver?

I have an IntentService which is called from elsewhere (say from component X) in my app. I want its onHandleIntent to run with a wake lock. There seem to be two ways of doing this:
Acquire and release a wake lock in onHandleIntent.
Create a new WakefulBroadcastReceiver which starts this service. In component X, call this receiver instead of the service directly.
The second option seems to be recommended. But why? Does the added indirection and boilerplate offer any advantage over the first approach?
Back in 2010, we were told that the only guarantee with AlarmManager and _WAKEUP-style alarms was that if we used a broadcast PendingIntent, then Android would keep the device awake long enough for onReceive() to complete. Any other type of PendingIntent did not have that sort of guarantee.
However, onReceive() of a BroadcastReceiver is called on the main application thread, and we cannot safely spend much time there. Ideally, it's sub-millisecond, as for all you know, your UI happens to be in the foreground right now, and you do not want this receiver to cause jank.
So, the recipe became:
Have the alarm trigger a BroadcastReceiver
Have the receiver acquire a WakeLock
Have the receiver delegate the work to a Service, typically an IntentService
Have the service release the WakeLock when the work is completed
My WakefulIntentService was the first library to offer support for this recipe. WakefulBroadcastReceiver came along later. They both accomplish the same end, just with different semantics.
Note that "why don't we just acquire a WakeLock in the service?" fails because the device might fall asleep between the end of onReceive() and the first place where the service might get a chance to acquire the WakeLock.
Now, for other situations, not involving AlarmManager, having the service manage its own WakeLock is perfectly reasonable. In fact, that's one of the reasons I went with having a special IntentService (WakefulIntentService) rather than a special BroadcastReceiver (WakefulBroadcastReceiver).

Do BroadcastReceivers need to be their own process to be independent from the UI (activities)?

So I'm working on an app that uses the AlarmManager to broadcast an intent for my receiver to do a simple task and finish quickly. I want my receiver to run every few minutes so I use setRepeating to ensure this. I don't want to have to worry about the main activity of my app running or being visible when the alarm triggers. In order for my receiver to run separately from the main activity like that, do I need to add android:process=":remote" to the receiver in the manifest? or are they already inherently separate things? The two do not need to communicate. I'm trying my best to kill the activity without canceling any alarms and the receiver seems to be running properly for now, but I'm wondering if it'll continue to work for a few hours or days.
Yes, they're separate. No need to use that attribute.
By the way, how much work do you do in that BroadcastReceiver? Normally, you can't do very much inside the BroadcastReceiver itself, you use it to trigger other things.
Also, I'm wondering how you're doing the following:
"I'm trying my best to kill the activity..."
I'm wondering what problem you were trying to solve here by trying to kill the activity?
To your immediate question - certainly not - it will be a performance killer and is unneeded anyway.
To your design - flawed. You should :
Register an alarm (also take care to re-register it on boot) - see wakeLock does not wait for network connectivity for the code registering the alarm
When the AlarmaManager wakes your receiver up delegate to a WakefulIntentService. The intent service is NOT guaranteed to run when the device is asleep (see Android deep sleep and wake locks).
See also:
PowerManager.PARTIAL_WAKE_LOCK android
PowerManager wakelock not waking device up from service for the WIS skeleton
WakefulIntentService implementation clarifications

Android: Running service in background forever

I don't know why, but my Service ( started with startService(Intent...) ) keeps closing after a while. I want my Service to check every 2 minutes the position with WiFiSLAM, therefore a TimerTask is running in the Service. I realized that my Service is shutting down after the App is closed (onDestroy) and the screen turned off.
I've read about the WakeLock and tried this:
final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
wakeLock.acquire();
But it still does not work. I don't know what to do. I just want to have my Wifi Positioning Framework to update the position in the background every two minutes.
I also set the return value of onStartCommand() to START_STICKY. Maybe it is running in the background, but I can't see the Logs in the LogCat when it is running for a while, which gives me signals that the indoorLocationManager is still catching new positions.
Someone has an idea?
Android automatically kills applications running in background for long periods (between 30 minutes and 1 hour).
The only way to prevent this is setting your service as foreground service.
To do that, you use the following:
startForeground(messgae, notification);
This will show a permanente notification informing the user that your service is running.
Other option, is to use AlarmManager to start an IntentService every 2 minutes.
Regards.
I have in the past had the ame problem, and you may not want to do this, however it does work for me. I set up 2 Services, the main worker, and a helper. The helper, every so often will make sure the worker is running, and the worker will ensure that the helper stays running. In this example, if one of them happens to get killed by the system, it will be relaunched by the other. I have never had both of them die at the same time.
Again, this is my solution that may not be something that you would like to do.
One solution is to use an alarm that launches you service at two minute intervals, or whatever you decide. However doing this will drain the battery, so keep that in mind.

using broadcast recevire with alarm manager in android

Why is it suggested generally to pass a pending intent for an Intent Service when using alarm manager? The same thing can be done in the onreceive() function of the broadcast receiver called by the alarmmanager. What is the advantage with using a service(Intent Service)?
If everything that you need done can be completed in onReceive of a BroadcastReceiver, then you should use that, not an IntentService.
If you want to do anything after the BroadcastReceiver, then you should use the IntentService. For example, if you want your BroadcastReceiver to start a Service, and you want the service to gain a WakeLock, then you should be using an IntentService instead.
The reason is that AlarmManager only guarantees that the onReceive of a BroadcastReceiver will be run, even if you use RTC_WAKEUP. So, it is slightly possible that if you use the BroadcastReceiver/Service combination, then the CPU will fall asleep before the Service can acquire the WakeLock - this is, unless you acquire a WakeLock in the BroadcastReceiver and you acquire one in the service, perhaps via a static WakeLock. But this is... messy, I suppose.
Btw, I have never implemented an IntentService. I just use the BroadcastReceiver and Service combo and have never had a problem reported. All the information I provided are things I read from other SO posts (primarily from CommonsWare)
EDIT:
The 50ms time frame I read from something CommonsWare posted on StackOverflow, and CommonsWare seems to be a rather reliable source of knowledge for Android.
I looked it up and, The docs do say:
(there is a timeout of 10 seconds that the system allows before
considering the receiver to be blocked and a candidate to be killed).
And they also say:
If this BroadcastReceiver was launched through a tag, then the object is no
longer alive after returning from this function.
You should not do anything that takes close to 10 seconds, just to be safe.
If you do anything that has to wait for a response, the BroadcastReceiver will die because the onReceive will likely finish running before you get the response back.
Though, I suppose the reason for the 50ms time frame is so you don't risk causing an ANR or any lag. Because if you use a Service, then you can start a new Thread, and it will not block. You would not be able to start a new Thread in a BroadcastReceiver because the code after the thread would continue to run, the BroadcastReceiver would die, and then the Thread would die, too.

Categories

Resources