Android Alarm manager working, but delayed - android

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

Related

AlarmManager not triggering repeated alarm on proper time

I am developing an application for Android Lollipop and KitKat devices. The application needs to call an API in every predefined interval (Based on the interval received from server). I am doing this using AlarmManager class.
But the problem is it works till some time then stops.
Say for example If I set to start the alarm at 08:00 AM with an interval of 30 minutes it works till 11:00AM (aprx) and then alarm doesn't trigger.
If I set a long interval (eg : 8 hours from current time, still same issue happens, not reiggering even once )
Code
public void setRepeatedAlarm(Context context, int requestCode, long next, long interval, Intent intent) {
PendingIntent sender = PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, next, interval, sender);
}
Function calling
AlarmHandleManager.get().setRepeatedAlarm(this, Constants.SchedulerRequestCodes.UPLOAD_LOG, date.getTime(), AlarmManager.INTERVAL_DAY, intent);
Let me know if any one can figure out the issue.
Have seen a bug reported in lollipop in Google bug tracker, If that is the case let me know if there is any alternative solution for this.
i don't think it's a bug since it's already mentioned in the official documentation
Note: As of API 19, all repeating alarms are inexact. Because this method has been available since API 3, your application can safely call it and be assured that it will get similar behavior on both current and older versions of Android.
Note: as of API 19, all repeating alarms are inexact. If your application needs precise delivery times then it must use one-time exact alarms, rescheduling each time as described above. Legacy applications whose targetSdkVersion is earlier than API 19 will continue to have all of their alarms, including repeating alarms, treated as exact.
Note: Beginning with API 19 (Build.VERSION_CODES.KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, android.app.PendingIntent) and setExact(int, long, android.app.PendingIntent). Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.

Alarm Manager not Triggering Properly

If the following line of code is used, the Alarm is triggered immediately by AlarmManager, which is normal since Android documentation states that if an Alarm is set in the past it will be triggered immediately.
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 60*60*24*1000, alarmIntent);
Meanwhile, by setting it to trigger 1 minute later, using the code here after adding +60*1000 to System.currentTimeMillis(), the Alarm will not be triggered 1 minute later, as it should (actually the Alarm will never be triggered, even after waiting for 10 additional minutes - perhaps it will the day after, when repeating, but I have not tested this yet).
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+60*1000, 60*60*24*1000, alarmIntent);
Depending on your API level.
Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS
will shift alarms in order to minimize wakeups and battery use. There
are new APIs to support applications which need strict delivery
guarantees; see setWindow(int, long, long, PendingIntent) and
setExact(int, long, PendingIntent). Applications whose
targetSdkVersion is earlier than API 19 will continue to see the
previous behavior in which all alarms are delivered exactly when
requested.
https://developer.android.com/reference/android/app/AlarmManager.html

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

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.

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();
}
}

AlarmManger malfunctioning in android ?

I have to call a service in every day on a particular time.obviously i had choose AlarmManager for waking up my service.and all working well other than AlarmManager triggering immediately when i set the past time.but it's working fine when i set time after current time.
For better clarification i will say an example.
WORKING ATTEMPT : Current time is 09.00 AM am setting schedule as
10.00 AM.And AlarmManager doing his job perfectly.
FAILURE ATTEMPT :Current time is 10.00 AM am setting schedule as
09.00 AM.And AlarmManager calls the services immediately.
Actually i need to invoke my service tomorrow 09.00 AM as the scheduled time is past.
I referred some query almost matching this one but it wasn't good enough.What i am doing wrong ?
My Code
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY,10);
calendar.set(Calendar.MINUTE, 00);
calendar.set(Calendar.SECOND, 00);
Intent myIntent = new Intent(MainActivity.this, MyReceiver.class);
myIntent.putExtra(ACTION, ACTION_SC_1);
PendingIntent pendingIntent = PendingIntent.getBroadcast(MainActivity.this, REQUEST_CODE_SC_1, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getBaseContext().getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);
Dont use alarm manager use GcmNetworkManager which was introduced in the last IO. It will work like a charm and you will have the ability to set in to inexact alarm so u wont need to wakeup the device. From the google IO site : Google Play Services has added the GCM Network Manager which functions mostly like JobScheduler, but extends to prior releases before Lollipop.
From the documentation
Like set(int, long, PendingIntent), except you can also supply a period at which the alarm will automatically repeat. This alarm continues repeating until explicitly removed with cancel(PendingIntent). If the stated trigger time is in the past, the alarm will be triggered immediately, with an alarm count depending on how far in the past the trigger time is relative to the repeat interval.
It is working intentionally like this.
As Bonatti said above, this is documented behaviour of the API when you set a time in the past.
You will need logic in your app to push out the alarm by 24hrs if it is already past 10am at the time when you want to set the alarm.
The easiest way to do this is probably to use the Calendar object as you have, then query
if (calendar.after(SystemClock.currentTimeMillis()) {
// Push alarm out til tomorrow.
calendar.add(Calendar.DAY_OF_MONTH, 1);
}
If you need the alarm to be triggered at 9AM sharp, don't use setRepeating() as it will not launch at the exact time since Android KitKat (this is also documented, you should really read the docs).
Use Calendar to build the timestamp from your desired alarm time. Check if the result timestamp is smaller than the current timestamp System.currentTimeMillis(), in that case it's in the past so add 24 hours to it to schedule it for the next day.
Finally, use AlarmManager.set() on older versions or AlarmManager.setExact() on newer versions of Android to schedule your alarm. Once the alarm goes off, you can schedule the next one using the same technique.

Categories

Resources