Periodic call in android every 90 seconds, even when app is closed - android

The requirement is to record the position every 90 seconds and write it to database(sqlite) and if network is available then call an api, even if the app is closed.
Which will be the best possible way to achieve this?
Should I start an intent service? Or I should go with an alarm Manager. I have read somewhere that alarm manager should only be used if the duration is more than 10 minutes.

I suggest to use AlarmManager since it can be run even Device is asleep.
Note that, for API v > 19, the alarm delivery is inexact and you have to use setExact api to achieve that .
See
Note: Beginning in API 19, the trigger time passed to this method is treated as inexact: the alarm will not be delivered before this time, but may be deferred and delivered some time later. The OS will use this policy in order to "batch" alarms together across the entire system, minimizing the number of times the device needs to "wake up" and minimizing battery use. In general, alarms scheduled in the near future will not be deferred as long as alarms scheduled far in the future.
With the new batching policy, delivery ordering guarantees are not as strong as they were previously. If the application sets multiple alarms, it is possible that these alarms' actual delivery ordering may not match the order of their requested delivery times. If your application has strong ordering requirements there are other APIs that you can use to get the necessary behavior; see setWindow(int, long, long, PendingIntent) and setExact(int, long, PendingIntent).

Alarm Manager would be the ideal choice for your situation. Registered alarms are retained while the device is asleep, but will be cleared if it is turned off and rebooted.
So, you can use this to run your job in 90 seconds interval. It may break the interval only first time after the device is rebooted.

Another way I found out was using the Firebase job dispatcher. That is the best option for devices running on marshmallow or further. It is easy to integrate and customizable.
https://github.com/firebase/firebase-jobdispatcher-android

A Service is an application component that can perform long-running
operations in the background and does not provide a user interface.
https://developer.android.com/guide/components/services.html
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.
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.
https://developer.android.com/reference/android/app/AlarmManager.html
Go with the service.

You go with Intent service and Broadcastreceiver componenst, because those components only listen continuously, even if you close the Application.
And you want to get something evry 90 seconds, so use Alarm Manager.
AlarmManager manager = (AlarmManager) (context)
.getSystemService(Context.ALARM_SERVICE);
Intent alarmIntent = new Intent(context, YourAlarmReceuver.class);
//alarmIntent.putExtra("syncData", favoritesArrayList);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,
alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
manager.setInexactRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(), 90*1000, pendingIntent);
Your Receiver class Like this
public class SyncAlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent stIntent = new Intent(context,
YourService.class);
context.startService(stIntent);
}
And Your Intent Service Class like this
public class DataSyncService extends IntentService {
public DataSyncService() {
super(DataSyncService.class.getName());
// TODO Auto-generated constructor stub
}
#Override
protected void onHandleIntent(Intent intent) {
//write your logic here
// get the location and update the database
}
}
You should instantiate the alarm manager boot completed also.

Related

Android AlarmManager not working when set for longer time [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
In my app I have tried to set an alarm using this code:
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 2016);
calendar.set(Calendar.MONTH, 1);
calendar.set(Calendar.DAY_OF_MONTH, 1);
calendar.set(Calendar.HOUR_OF_DAY, 15);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 1);
calendar.set(Calendar.MILLISECOND, 1);
Intent intent = new Intent(G.context, AlarmService.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext, 1010, intent, PendingIntent.FLAG_UPDATE_CURRENT);
G.alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
It works when I set the alarm for 1 minute or later, but not when I set the alarm for 30 or 40 minutes later. While I am not on the phone for 30 minutes, after 30 minutes the alarm did not work, and when the phone screen is on the alarm worked...
Any help would be appreciated.
Ok that's because after a long time (let's say more than 5 min) your app is Paused and then the phone is "asleep" with lock screen. When you unlock it then you get your Alarm because it was queued.
To solve this problem, you need to implement a Wake Lock and add it's permission to your manifest file.
According to Google Documentation "A wake lock is a mechanism to indicate that your application needs to have the device stay on."
This is the line you have to add in your manifest:
<uses-permission android:name="android.permission.WAKE_LOCK" />
You'll need to implement this object in your onReceive() method in your BroadcastReceiver. You can follow this tutorial that makes use of all you need.
https://www.javacodegeeks.com/2012/09/android-alarmmanager-tutorial.html
Also, note that you'll keep the device "awake" therefore you'll keep the phone processing affecting the battery life, but still you get to be able to get the alarm even if the screen is locked.
Hope it helps!
Since API 19 set() is treated as inexact and may be delayed. If you really need a precise alarm, you should use setExact() (available since API 19) instead :
Note: Beginning in API 19, the trigger time passed to this method is
treated as inexact: the alarm will not be delivered before this time,
but may be deferred and delivered some time later. The OS will use
this policy in order to "batch" alarms together across the entire
system, minimizing the number of times the device needs to "wake up"
and minimizing battery use. In general, alarms scheduled in the near
future will not be deferred as long as alarms scheduled far in the
future.
This change happen on 19+ device (obviously) but also only if the APK's target API is 19+, so you can
change the target API to 18
or use Build.VERSION.SDK_INT to know which method to use.
Additionnaly when you use a *_WAKE_UP alarm, the alarm manager garantees that the device will be awake long enough to execute the receiver's method, but not the service it may launch :
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.
The support v4 library provides a usefull helper class to handle this case : WakefulBroadcastReceiver
In you case, as you are using a service pending intent, I am not sure what wake garanties apply.
i use service
public class AlarmService extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onStart(Intent intent, int startid) {
//This is my Code and set Alarm
stopSelf();
}
}

Track per app usage on android on pre-Lollipop devices

I would like to build an app that can track how long a user spends on certain apps (mainly for proof of concept and to implement in other apps.) I know that Lollipop implemented the API UsageStatsManager that enables you to track the "total length of time an app was in the foreground for a time interval (by day, week, month, or year)."
I have also read that one can poll the AcvtivtyManager continuously, however that would waste battery life and take up CPU and RAM.
What I am wonder is, is there an efficient way to keep track of the amount of time an app is open on devices running an android version lower than Lollipop. Specifically how apps like Aptrax and App Usage Tracker as well as many others, do it with very little or "No battery drain (even on high frequency tracking)."
Is there another method that these apps use, to get app usage data on pre-Lollipop devices, with little battery usage, or is polling the Activity manger not as resource heavy as they source I read lead me to believe.
i have tried to do the same but found no better way, basicklly poll the activity manager, now to make sure not to waste battary use the alarmManager and a recieverto set the waking times of the pollin so that when the phone is asleep it wont be woken for your poll (assume that user uses apps when the screen is on and phone is active) and poll like every 5 seconds or so
here is basic sample code
Intent alarmIntent = new Intent(context, MyReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC, Calendar.getInstance().getTimeInMillis(), pendingIntent);
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, Intent intent) {
// poll activity manager and any thing else you want here
// including figuring out the next time you want to run
// and scheduling another PendingIntent with the AlarmManager
}
}
using AlarmManager.RTC makes sure the reciever is only polling when the phone is awake.

Android Alarm manager working, but delayed

I would like to make a delay(10 min) for user then after it, user can edit something.
to do this,I created a setAlarm function :
public void setAlarm(Context context,int user,int time) {
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, sef_time.class);
intent.putExtra(ONE_TIME, Boolean.FALSE);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
am.set(AlarmManager.RTC, 1000*60*time , pi);
}
everything works fine, but my alarm manager has a delay.
for example:
setAlarm(.....,int 10);
It has a delay : 00:10:03 second or 00:10:10 second 00:10:20 second !
where is my wrong ?
As you can see here:
Beginning in API 19, the trigger time passed to this method is treated
as inexact: the alarm will not be delivered before this time, but may
be deferred and delivered some time later. The OS will use this policy
in order to "batch" alarms together across the entire system,
minimizing the number of times the device needs to "wake up" and
minimizing battery use. In general, alarms scheduled in the near
future will not be deferred as long as alarms scheduled far in the
future.
With the new batching policy, delivery ordering guarantees are not as
strong as they were previously. If the application sets multiple
alarms, it is possible that these alarms' actual delivery ordering may
not match the order of their requested delivery times. If your
application has strong ordering requirements there are other APIs that
you can use to get the necessary behavior; see setWindow(int, long,
long, PendingIntent) and setExact(int, long, PendingIntent).
Applications whose targetSdkVersion is before API 19 will continue to
get the previous alarm behavior: all of their scheduled alarms will be
treated as exact.
If it's very important that the alarm be exact, use setExact (When the device's SDK is 19 or above).
The easiest way to make system have a delay and then sound an alarm at the exact specified time is using setExact(), and the code can be something like this.
am.setExact(AlarmManager.RTC_WAKEUP,System.currentTimeMillis() + (time_you_want_to_delay_in_milliseconds) ,pi);

Performing a Scheduled task from a Service and Keeping that service Alive

public class MyHibernatedService extends Service{
public void onCreate() {
super.onCreate();
//declaring the intents ..
//some codes...
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, IntentServiceToBeRun, 0);
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MILLISECOND, 10000);
am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
}
}
I want my Service to launch an IntentService every single day at a certain time. However, I've read somewhere on the internet, StackOverflow, google,etc.. that a Service cannot stay alive forever, this is how Android works. It will have to kill that Service whenever Android needs memory or is using too much memory.
What guarantees for me that this code will run everyday and my Service will not be killed?
EDIT :
I noticed in the Android docs:
The Android system will attempt to keep the process hosting a service around as long as the service has been started or has clients bound to it
what do they actually mean by "clients bound to it"?
Don't use your own service to periodically start another service, but use the AlarmManager service instead (like you are already doing). There is no need for this second service IMHO.
The AlarmManager is a system service and will never be killed by Android, and it already does exactly what your own service would do: start things periodically (or single-shot at a specified time).
On the "clients bound to it": off-topic, but it means other components (like other services, or activities) are connected to it using a call to Context.bindService(). For details, check the dev guide.
You don't actually need to keep your service alive.
Here you are setting the AlarmManager, that is able to wake your IntentService up when it is time, even if the phone is sleeping. This service does the job, not yours.
What guarantees for me that this code will run everyday and my Service
will not be killed?
The code that you provided in MyHibernatedService has to be executed only once, to set the alarm, then you won't need it anymore. If it is the only thing that MyHibernatedService does, then you don't need it at all.
You could for instance create a static method in your intent service that would set the alarm, and call it from anywhere according to what you want (probably the place where you used to start MyHibernatedService).
Also, if you don't really need an incredible accuracy on the time your intent service is started, prefer setInexactRepeating() instead of setRepeating().

Android: correct way to use AlarmManager without draining battery

I need to do a background check in my app, basically polling various URLs for new stuff. So I've read this is done with the AlarmManager.
The thing is, I don't need the user to be notified as soon as new stuff arrives. Let's say I'm checking every hour, I'm perfectly fine with not doing any check while the phone is sleeping, and resuming the checks when the phone is used. That way the user eventually gets the notification, but the drain is minimal.
So I've tried with setInExactRepeating. I'm starting it at boot time, but also at app startup (mostly for the session after install, and to make sure it's running even if the app gets "force killed"). How do I prevent all these checks to add up? (A new check should only be run if none is running, or the previous one needs to be stopped).
I've found setInexact Repeating coupled with ELAPSED_REALTIME (or RTC) works quite well to achieve very minimal battery drain. Using the flag FLAG_UPDATE_CURRENT on an existing pendingintent (same intent and id) will simply refresh the current alarm schedule if it already exists. Alternatively, add the code suggested by Ralgha to check and see if you already created the pending intent and set the alarm, and then if not, set the pending intent and alarm schedule. Both methods will likely have the same impact on battery (negligible). What will cause significant drain is doing something on a frequent schedule. The fact that you only want to update every hour and not when the screen is off, your app will use barely any battery (assuming it is done with it's processing relatively quickly and cleans up after itself nicely)
http://developer.android.com/reference/android/app/AlarmManager.html#ELAPSED_REALTIME
ELAPSED_REALTIME
This alarm does not wake the device up; if it goes off while the device is asleep, it will not be delivered until the next time the device wakes up.
http://developer.android.com/reference/android/app/AlarmManager.html#setInexactRepeating%28int,%20long,%20long,%20android.app.PendingIntent%29
setInexactRepeating
These alarms are more power-efficient than the strict recurrences supplied by setRepeating(int, long, long, PendingIntent), since the system can adjust alarms' phase to cause them to fire simultaneously, avoiding waking the device from sleep more than necessary.
http://developer.android.com/reference/android/app/PendingIntent.html#FLAG_UPDATE_CURRENT
FLAG_UPDATE_CURRENT
...if the described PendingIntent already exists, then keep it but its replace its extra data with what is in this new Intent. This can be used if you are creating intents where only the extras change, and don't care that any entities that received your previous PendingIntent will be able to launch it with your new extras even if they are not explicitly given to it.
You can check to see if the alarm is already set before you set it, and you can also use a flag so the alarm won't be delivered until the device is awake.
if ( PendingIntent.getBroadcast( context, 0, updateIntent, PendingIntent.FLAG_NO_CREATE ) == null )
{
pendingIntent = PendingIntent.getBroadcast( context, 0, updateIntent, 0 );
getSystemService( ALARM_SERVICE ).setInexactRepeating( AlarmManager.RTC, System.currentTimeMillis(), AlarmManager.INTERVAL_HOUR, pendingIntent );
}

Categories

Resources