Which is Better ScheduledExecutorService or AlarmManager in android? - android

I am a beginner and I am developing an android application which will keep on sending SMS to the user after a certain delay (which is in days).I want that the user once registered should receive the SMS irrespective of the fact that he is logged in or not. The SMS content and mobile number are fetched from the database.So after researching I found two ways
ScheduledExecutorService
AlarmManager
The problem is that the alarmManager will shut down when the phone is switched off or rebooted. Is this the case with ScheduledExecutorService too? And how many threads should I use in the ThreadPool while using the Executor Service?

Alarm Manager
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.
ScheduledThreadPoolExecutor.
You can use java.util.Timer or ScheduledThreadPoolExecutor (preferred) to schedule an action to occur at regular intervals on a background thread.
Here is a sample using the latter:
ScheduledExecutorService scheduler =
Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate
(new Runnable() {
public void run() {
// call service
}
}, 0, 10, TimeUnit.MINUTES);
So I preferred ScheduledExecutorService
But if the updates will occur while your application is running, you can use a Timer, as suggested in other answers, or the newer ScheduledThreadPoolExecutor. If your application will update even when it is not running, you should go with the AlarmManager.
The Alarm Manager is intended for cases where you want to have your application code run at a specific time, even if your application is not currently running.
Take note that if you plan on updating when your application is turned off, once every ten minutes is quite frequent, and thus possibly a bit too power consuming.
Also check out this post.

Related

Network call on alarm times out

I have an app that uses AlarmManager to schedule a repeating alarm every X amount of time. When my receiver receives the Intent, it has to make a http request.
The alarm itself works fine and triggers when it should. The network call, however, starts timing out when the phone is not in use. To be more specific:
When I schedule it to fire every minute (bad practise, I know, but just to illustrate), the first 5-8 minutes the request succeeds. After that, I get a java.net.SocketTimeoutException: connect timed out. Sometimes it does succeed, but mostly this happens.
I tried setting the connect/read/write timeouts to a minute, but then I get this exception instead of the one above: java.net.ConnectException: Failed to connect to myapp.example.com/123.45.67.89:80.
My code:
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Consider mApi and myBody to be initialised and valid
mApi.myPostRequest(myBody).enqueue(new Callback<Void> {
#Override
public void onResponse(Call<Void> call, Response<Void> response) {
//Does not get here
}
#Override
public void onFailure(Call<Void> call, Throwable t) {
t.printStackTrace();
}
}
}
}
Things I've tried:
as stated before, increasing timeouts
acquiring a WakeLock in
onReceive and releasing it when the call is done (added the
permission)
Other information:
The alarm is set using
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(), interval, pendingIntent); from my
Activity.
I'm using Retrofit (2.1.0) for the network communication, but you could probably have guessed that from my code ;)
Any ideas on how to get the network call working when the phone is sleeping?
You Should use JobService here, it has many constraint to handle different scenarios and also your Job is guaranteed to be executed by the system.
The problem here is of doze mode, and using JobService this can be resolved easily.
Implementation is also easy all you need to do is create a JobService and inside it's onStartJob() start your network thread and then just dispatch your job.
For more detail
https://developer.android.com/reference/android/app/job/JobService.html
From https://developer.android.com/reference/android/content/BroadcastReceiver.html
As a general rule, broadcast receivers are allowed to run for up to 10
seconds before they system will consider them non-responsive and ANR
the app. Since these usually execute on the app's main thread, they
are already bound by the ~5 second time limit of various operations
that can happen there (not to mention just avoiding UI jank), so the
receive limit is generally not of concern. However, once you use
{#goAsync }, though able to be off the main thread, the broadcast
execution limit still applies, and that includes the time spent
between calling this method and ultimately PendingResult.finish().
Further reading says
If you are taking advantage of this method to have more time to
execute, it is useful to know that the available time can be longer in
certain situations. In particular, if the broadcast you are receiving
is not a foreground broadcast (that is, the sender has not used
FLAG_RECEIVER_FOREGROUND), then more time is allowed for the receivers
to run, allowing them to execute for 30 seconds or even a bit more.
(long work should be punted to another system facility such as
JobScheduler, Service, or see especially JobIntentService),
You can try using #goAsync. Or you can switch your logic to JobIntentService
I haven't tested any of these.
You have a basic mistake in your code - you cannot make requests (or any long running operations) in your broadcast receiver - it dies after ~10 sec so that might be the reason for some of your failures.
You should move the request logic to a service (IntentService) which you'll start from your broadcast receiver and make the request there.
That should work just fine.
From developer docs : https://developer.android.com/reference/android/app/AlarmManager.html
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
In your code onReceive will return before mApi.myPostRequest(myBody).enqueue ...task will be executed, then this task probably will be never executed due the CPU will stop as soon onReceive returns.
You said you tested acquiring a WakeLock, but new Android 6.0 Doze mode ignores wakelocks
It seems that OnReceive will have to wait for the task to end
Some ideas:
Checking for some terminate flag in a loop with thread.sleep ?
If the task uses a Thread object then using thread.join() ?
You should use AlarmManager.RTC_WAKEUP, not AlarmManager.ELAPSED_REALTIME_WAKEUP to wake up device and you should use a service to do your job started in Received in onReceive with startWakefulService(context, service.class). This will ensure that device will fully wake up and do your network call without timeout.
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, SystemClock.elapsedRealtime(), interval, pendingIntent);
If the problem is caused by Doze and Wakelocks being ignored, you should try the tips offered in https://developer.android.com/training/monitoring-device-state/doze-standby.html:
Standard AlarmManager alarms (including setExact() and setWindow()) are >deferred to the next maintenance window.
If you need to set alarms that fire while in Doze, use setAndAllowWhileIdle() >or setExactAndAllowWhileIdle().
Alarms set with setAlarmClock() continue to fire normally — the system exits Doze shortly before those alarms fire.
there are 2 problems in your implementation:
1) if broadcast receiver doesn't get finished executing within 10 seconds then ANR will happen.
2) All network calls are optimized in the background, so when device is wake it may work else will not fire HTTP request to conserve battery and other resources.
what you should do is inside service create a loop (with sleep time of few seconds) that checks time on each iteration and when that time is reached then perform task, I have also faced such issues when tried to upload files to server at an interval of 1 hour, so I decided to work on my own rather than using AlarmManager class...
I hope this will help you...
Use Foreground service to get your job done.
Refer the official link for dive into Foreground service
By using Foreground service, we can set the interval to start doing an API call in the background without getting affected by the doze mode. follow this simple example that includes complete code and walkthrough.
happy coding. Thanks ;)

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).

TimerTask vs AlaramManager, Which one should I use?

I am working on an application which triggers an action (say toast message) every 10 minutes after the screen is ON and stops the action after the screen is OFF.
I have used TimerTask for this purpose.
Shall I start using AlaramManager instead of TimerTask or shall I keep using TimerTask ?
I know the difference between the two but can't figure out which to use.
Cant' agree with the nikis' answer
Timer and AlarmManager are solutions addressed to satisfy different needs.
Timer is still a "task" that means this is a thread of your application that means that some component of your application must be running on device to keep timer alive.
If you set timer for 10 minutes events - you can't be sure if your application will not be disposed by system in some moment. If device will be turned into the sleep mode your timer can be stopped. To prevent behavior like that you have to use PowerLock's and drain battery
AlarmManager is system service (runs outside your application) that means that the pending intent will be sent even if your application is killed after setting the alarm.
Some examples:
You have to blink some "led" on the view every 1 s - use Timer - you need it only when application is in foreground, there are short intervals - no point in using AlarmManager for task like that.
You have run some task once after 10 s - Handler.postDelay(); will be the best solution for that, and the job will be done on main thread (UI).
You have to check every 10 minutes if there is some new content on device that you are supposed to push to the server - use AlarmManager - your application does not need to be alive all the time, just let system to start job you want every 10 minutes - that's all.
In most cases you should definitely use AlarmManager, because (from the docs):
The AlarmManager 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 AlarmManager releases this wake lock. This means that the phone will in some cases sleep as soon as your onReceive() method completes.
Although you don't need to fire any event while screen is off, AlarmManager still saves the battery by grouping alarms, when you use setInexactRepeating (but this is not important for you, because your interval is 10 minutes). And moreover, it can fire an event is app is not running. I vote for AlarmManager, because it's good practice, but considering your conditions, you can leave Timertask.
BTW, you can also use Handler, which I believe will be the best choice.

Application exit to keep it in background for some times

I am working on Android app where i using a service to fetch location on a time interval using timer. But if I keep my app in back ground for some time then application exit and its onCreate() method is re Called and my timer stops please tell me how I can keep running my application for long times.
timer = new Timer();
timerTask = new TimerTask() {
#Override
public void run() {
}
};
timer.schedule(timerTask, 1000*60*4, 1000*60*4);
A service that runs for a longer period of time is only worth its execution (and energy consumption) time if it delivers value to the user continually. It's not the case of a location poller, which only delivers value for short periods of time, depending on what you do with the polled location. In this case you should implement a service that will perform a short task (I mean task in the general sense, not a Task object) and then you must schedule your service to run from time to time. You can use Android's scheduling mechanism, called AlarmManager, to schedule your services.
There is a problem inerent to this approach, though: when the system is in battery-saving sleep state, your service has to acquire a wake lock in order to execute properly, then when finished release the wake lock for the system to go back to sleep state. Implementing this wake lock acquisition/release mechanism is not a trivial task.
I suggest you to use Commonsware's Location Poller implementation instead of implementing one yourself. It is well tested and solves the issue of acquiring/releasing a wake lock for your service to execute in the background.
If you insist in doing the polling yourself (e.g. to put already written code to use), I recommend using Commonsware's WakefulIntentService in order to avoid writing your own wake lock acquisition/release mechanism for your service. It's very easy to use.
Your solution for long running tasks is to use an Android Service.
A Service is an application component representing either an application's desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use. Each service class must have a corresponding declaration in its package's AndroidManifest.xml. Services can be started with Context.startService() and Context.bindService().

Beginner questions: Wakelocks

I am new to the notion of WakeLock and need your help.
Questions:
I assume WakeLock to be some type of lock which when held by the executing code prevents the device from sleeping. What if the device is already in sleep/standby mode, will the code execute then? Assuming that it would never acquire a WakeLock?
When a long running task(abt 7-8 sec) is done in a background thread(AsyncTask) should I be bothered about holding a WakeLock? Does AsyncTask already acquire it for me?
links to official documentations and writeup on wakelocks are appreciated.
Thanks.
1.If the phone is in full sleep mode, aside from an incoming phone call, you could use an AlarmManager intent to wake the phone up.
From the AlarmManager class documentation:
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.
2.If you're working with an AsyncTask, you will want to publish results on to the UI thread on onPostExecute()
From the AsyncTask documentation:
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
3.I suggest you have a read at the official documentation of Power Manager which gives a good introduction to the WakeLock concept.
Typically the only code that would run while the phone is sleeping is a BroadcastReceiver. Actually, the phone wakes up for a second, runs the BroadcastReceiver's code and sleeps again. Since you should never run long code in a BroadcastReceiver (use it to launch a Service instead), you can basically assume that your code is never run while the phone is sleeping. Of course, if you are using a BroadcastReceiver to start a Service, you should usually obtain a WakeLock.
With an AsyncTask initiated by the user, you don't really need to worry about WakeLocks. It is unlikely the phone will sleep while it is running. I'm not sure if they get a WakeLock, but putting my phone to sleep while running a standard AsyncTask doesn't seem to interrupt the it.
As SteD said, check this out: http://developer.android.com/reference/android/os/PowerManager.html
Basically the only time you need to worry about WakeLocks is when you either expect your task to be interrupted by sleeping (as is the case if you set an alarm that wakes the phone up briefly) or if you absolutley cannot have the task interrupted. Otherwise, just make sure that you gracefully handle any interruptions.

Categories

Resources