MonoDroid - Daily scheduled service using alarm manager? - android

I am trying to schedule a service to run daily at a user specified time. I am using a timepicker to give the user control over what time of day the service is run.
Each time the user changes the time of day for the service to run I am updating the alarm manager.
Here is my code to do this:
void RescheduleOpeningRatesRetriever (string strTime)
{
var i = new Intent (this.ApplicationContext, typeof (OpenRatesService));
var src = PendingIntent.GetService (this.ApplicationContext, 0, i, PendingIntentFlags.UpdateCurrent);
var am = (AlarmManager)this.ApplicationContext.GetSystemService (Context.AlarmService);
var hour = TimePickerPreference.GetHour (strTime);
var minute = TimePickerPreference.GetMinute (strTime);
var cal = Java.Util.Calendar.GetInstance (Java.Util.TimeZone.Default);
cal.Set (Java.Util.CalendarField.HourOfDay, hour);
cal.Set (Java.Util.CalendarField.Minute, minute);
am.SetRepeating (AlarmType.RtcWakeup, cal.TimeInMillis, AlarmManager.IntervalDay, src);
}
I am not 100% sure if the code is scheduling the service to run properly as I have had mixed results from my tests.
The problem that I am experiencing now is each time I re-schedule the service to run with the above code, the service is started instantly.... I don't want to start the service until the configured time of day.
How can I schedule and update the service to run at a specified time of day without running the service instantly upon scheduling it with the alarm manager?

If the time for which you are setting the alarm is in the past then the alarm will goes off instantly. so first check whether the time is in past, if it is then set it for next day.
like::
Calendar rightNow = Calendar.getInstance()
if( cal.after( rightNow ) )
{
am.SetRepeating (AlarmType.RtcWakeup, cal.TimeInMillis, AlarmManager.IntervalDay, src);
}
else
{
cal.roll(Java.Util.CalendarField.DAY_OF_MONTH, 1);
SetRepeating (AlarmType.RtcWakeup, cal.TimeInMillis, AlarmManager.IntervalDay, src);
}

Related

AlarmManager time not being set correctly

I am developing an app where I use an AlarmManager to schedule a time to open an Activity.
The chosen time is picked by a TimePicker.
Despite the time being the expected one when I call the method when.getTime , my activity doesn't open at the specified time.
Getting the time
int hour = tp.getCurrentHour();
int min = tp.getCurrentMinute();
MedicationReminder mr = new MedicationReminder(getApplicationContext());
Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR, hour);
c.set(Calendar.MINUTE, min);
if (hour > 12) {
c.add(Calendar.HOUR, 12);
}
mr.setReminder(new Medication(name, quant_aux, time), c);
Setting alarm
Intent i = new Intent(mContext, MedicationReceiver.class);
i.putExtra("medName",medication.getName());
i.putExtra("medQuant",medication.getQuantity());
PendingIntent pi=PendingIntent.getBroadcast(mContext,0,i,0);
mAlarmManager.set(AlarmManager.RTC_WAKEUP,when.getTimeInMillis(),pi);
I tried replacing when.getTimeInMillis by 2000 and the activity opened , so the problem is not on my broadcast receiver.
Why is this happening?
Edit: I tried to schedule for the following minute and the acitivity opened.
I tried for the next 2 minutes and the activity opened with a delay of 12-15 seconds. Tried with 5 minutes and the activity didn't open
Try using setExact instead of set
...
mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, when.getTimeInMillis(), pi);
https://developer.android.com/training/scheduling/alarms

How to schedule a task using something other than Alarms and it should be easy to test and also should run even after device restart?

I have to run a receiver which receives action USER_PRESENT only for a particular duration on specific days of the week. Here the duration and weekdays are selected by user.
What I have tried is using Preferences with AlarmManager to achieve this and I would very much like to use something other than Alarms with Preferences to achieve this as It becomes too difficult to test alarms with weekly alarms that runs after user selected duration and for user selected week days.
Is there any other way I can do this work other than using Alarms and Preferences. A code sample would really helpful !!
For more details here is my approach using Alarms with Preferences :
Now Firstly I calculate the start time by letting user choose the hour and minutes through a DialogFragment where a TimePickerDialog is inflated so that user can choose the starting time and I get the hrs and min in the onTimeSet() callback and then I find out the start time for the receiver to go off.
Code Snippet goes something like this for calculating start time in millis from hrs and min:
Calendar calSet = Calendar.getInstance();
//setting alarm from current day so that it starts from today onwards
int day = calSet.get(Calendar.DAY_OF_WEEK);
calSet.set(Calendar.DAY_OF_WEEK, day);
calSet.set(Calendar.HOUR_OF_DAY, hrs);
calSet.set(Calendar.MINUTE, min);
calSet.set(Calendar.SECOND, 0);
calSet.set(Calendar.MILLISECOND, 0);
Long milliseconds = calSet.getTimeInMillis();
//check if the time is already passed
Long daily = 24L * 60L * 60L * 1000L;
if (milliseconds < System.currentTimeMillis()) {
//if already passed then push it for next day by adding just 24 hrs
milliseconds = milliseconds + daily;
}
And then I save this calculated time in millis in a preference say : SharedPreferences.Editor.putLong("PeriodicLockStartTimeInMillis", milliseconds);
Now I store the days user has selected using checkBoxes and setting preferences for each day's checkbox
SharedPreferences.Editor.putBoolean("DAYNAME", true);
also storing the duration for which the user wants the receiver to work:
SharedPreferences.Editor.putLong("LockDurationInMillis", minutesinmillis);
Then Using AlarmManager to set an alarm which will set a BroadcastReceiver whose name here is PeriodicLockServiceas an PendingIntent that will hit its receiver .
Code for setting alarm here :
Intent reminderIntent = new Intent(getActivity(), PeriodicLockService.class);
reminderIntent.setAction("ACTION_REPEATING_ALARM_RECEIVER");
pendingIntent = PendingIntent.getBroadcast(getActivity(), PeriodicLockService.REPEATING_ALARM_UNIQUE_ID, reminderIntent, PendingIntent.FLAG_UPDATE_CURRENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, milliseconds, pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, milliseconds, pendingIntent);
}
Now in PeriodicLockService when onReceive is hit then I firstly check if user had set things to run for today by using the preference as :
//Fetching today's day from Calendar to compare if user has set lock for today
Calendar calendar = Calendar.getInstance();
int day = calendar.get(Calendar.DAY_OF_WEEK);
switch (day) {
case Calendar.SUNDAY:
if (Preferences.getBooleanPreference(context, SUN_DAY)) {
startLockNow(context);
}
break;
case Calendar.MONDAY:
if (Preferences.getBooleanPreference(context, MON_DAY)) {
startLockNow(context);
}
break;
case Calendar.TUESDAY:
if (Preferences.getBooleanPreference(context, TUES_DAY)) {
startLockNow(context);
}
break;
case Calendar.WEDNESDAY:
if (Preferences.getBooleanPreference(context, WED_DAY)) {
startLockNow(context);
}
break;
case Calendar.THURSDAY:
if (Preferences.getBooleanPreference(context, THURS_DAY)) {
startLockNow(context);
}
break;
case Calendar.FRIDAY:
if (Preferences.getBooleanPreference(context, FRI_DAY)) {
startLockNow(context);
}
break;
case Calendar.SATURDAY:
if (Preferences.getBooleanPreference(context, SAT_DAY)) {
startLockNow(context);
}
break;
}
private void startLockNow(Context context) {
Long lockStartTimeInMillis = Preferences.getLongPreference(context, "PeriodicLockStartTimeInMillis");
//Update Unlock Time
Long LockDurationInMillis = Preferences.getLongPreference(context, "LockDurationInMillis"); //End time to stop the Receiver for action USER_PRESENT
Long newEndTime = lockStartTimeInMillis + LockDurationInMillis;
//Set Unlocked notification broadcast which also disables the receiver for action `USER_PRESENT`
Intent intent = new Intent(context, FinalUnlockedBroadcast.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, newEndTime + 1000, pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, newEndTime + 1000, pendingIntent);
}
//update the time for next lock by adding a day
milliseconds = Preferences.getLongPreference(context, "PeriodicLockStartTimeInMillis") + 24L * 60L * 60L * 1000L;
Intent reminderIntent = new Intent(context, PeriodicLockService.class);
reminderIntent.setAction("ACTION_REPEATING_ALARM_RECEIVER");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, REPEATING_ALARM_UNIQUE_ID, reminderIntent, PendingIntent.FLAG_UPDATE_CURRENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, milliseconds , pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, milliseconds , pendingIntent);
}
}
But the thing is this doesn't always seem to work and its difficult to get logs from users devices running my app.
Is there any other way I can do this work other than using Alarms and Preferences
Android-Job Android-Job repo
Android-Job abstracts away which implementation you want to use to perform background work.
Depending on the requirements, this library decides which API to use to run your job.
It provides a superset of all the features from JobScheduler, GCMNetworkManager and AlarmManager.
All features from Android Nougat are backward compatible.
Less boilerplate.
Implementing Android-Job is super easy.
The API includes below classes/interfaces.
Job : Your jobs need to extend this class and override onRunJob method. The heavy lifting is done here. You must return a Result from this method so that the system knows whether to attempt to run your job at a later time.
JobRequest: You can schedule a Job by creating a JobRequest using its builder constructor and passing your Job tag.
JobCreator: JobCreator acts like a factory to provide a Job based on a job tag. Your concrete JobCreator class must implement the JobCreator interface and override the create method.
JobManager: The JobManager class serves as the entry point. Before using this class you must initialize this as singleton. JobManager takes a Context. After creating the instance, you have to add your JobCreator to JobManager.
if u interested to read more plz take alook to this awesome article Easy Job Scheduling with Android-Job
thanks for Rajesh Pattanaik the person who wrote this article
I would recommend you Firebase Job Dispatcher. It is a library for scheduling background jobs in your Android app. It provides a JobScheduler-compatible API that works on all recent versions of Android (API level 9+) that have Google Play services installed.
For instructions on how to use it in your app, click here.
You can use Job Scheduler
public class MyJobService extends JobService {
#Override
public boolean onStartJob(JobParameters params) {
Toast.makeText(this, "testing", Toast.LENGTH_LONG).show();
Log.i("sid", "Job scheduler called");
jobFinished(params, true);
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
return false;
}
}
Call the below method in your activity
private void constructJob(){
JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, new ComponentName(this, MyJobService.class));
builder.setMinimumLatency(60000)
.setBackoffCriteria(10000,JobInfo.BACKOFF_POLICY_LINEAR)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
.setPersisted(true);
mJobScheduler.schedule(builder.build());
}
Make sure you call builder.setPersisted(true) in order to run the service even after reboot. Another thing to have a look is that this code will work fine on Android N (API 24) or above APIs, however, for API 21 - 23 it call builder.setPeriodic(60000) instead of builder.setMinimumLatency(60000)
UPDATE
In order to run Job Scheduler on API 15 and above use JobSchedulerCompat.
Add below dependency in your gradle file -
compile 'me.tatarka.support:jobscheduler:0.1.1'

Set AlarmManager only with TimePicker in Xamarin.Android, alarm starting instantly [duplicate]

This question already has an answer here:
Xamarin Android Alarm Manager Issue
(1 answer)
Closed 5 years ago.
I having trouble while trying to set an Exact Alarm with only a Time Picker.
I set a TimePicker with an Handler like this:
TimePicker
TPBtn.Click += delegate
{
TimePickerDialog dialog = new TimePickerDialog(this, TimeSelectedListener, DateTime.Now.Hour, DateTime.Now.Minute, true);
dialog.Show();
};
private void TimeSelectedListener(object sender, TimePickerDialog.TimeSetEventArgs e)
{
hour = e.HourOfDay;
minute = e.Minute;
DateTime dtNow = DateTime.Now;
int DayOfMonth = dtNow.Day;
int Month = dtNow.Month;
int Year = dtNow.Year;
Calendar cl = Calendar.Instance;
cl.Set(Year, Month, DayOfMonth, hour, minute, 0);
AlarmManager am = (AlarmManager)this.GetSystemService(AlarmService);
Intent intent = new Intent(this, typeof(OneShotAlarm));
intent.AddFlags(ActivityFlags.NewTask);
var source = PendingIntent.GetBroadcast(this, 0, intent, 0);
am.SetExact(AlarmType.RtcWakeup, cl.TimeInMillis, source);
Toast.MakeText(this, "Set Today: " + cl.TimeInMillis, ToastLength.Short).Show();
}
Unfortunately, when doing this the alarm is instantly played.
I also tried to use am.SetAlarmClock but I don't know how to use RTC time with it, can you help me please ?
I already read many thread like I am trying to set alarm on specific time using alarm manager but alarm intiated instantly? and Set AlarmManager from DatePicker and TimePicker
Thanks a lot.
am.SetExact(AlarmType.RtcWakeup, cl.TimeInMillis, source);
cl.TimeInMillis is called on Calendar.Instance which has not been manipulated in any way. So that means it is set to "now", hence the alarm firing immediately.
It is not exactly clear what time you want the alarm to fire, but you will need to provide the correct TimeInMillis to do so.

Android Automatic Task in a specific time

I am new in Android development. I am developing a twitter client. I would like to send a tweet at every morning at 8. I want to set the schedule like Alarm. How can I do that ? I will be happy if you point me to some examples or other resources. Thanks.
Here is an example of the AlarmManager:
private void daylyTask()
{
daylyBR = new BroadcastReceiver() {
#Override public void onReceive( Context context, Intent _ )
{
//Do something
Log.d(TAG, "daylyTask uitgevoerd.");
}
};
getApplicationContext().registerReceiver( daylyBR, new IntentFilter("yourApp.blah") );
daylyPendingIntent = PendingIntent.getBroadcast( getApplicationContext(), 0, new Intent("yourApp.blah"), 0 );
GregorianCalendar cal = new GregorianCalendar();
cal.set(GregorianCalendar.HOUR_OF_DAY, 0);
cal.set(GregorianCalendar.MINUTE, 0);
// set alarm to fire 5 sec (1000*5) from cal repeating every 86400000L ms (1 day)
manager.setRepeating( AlarmManager. RTC_WAKEUP, cal.getTimeInMillis() + 5000L, 86400000L, daylyPendingIntent );
}
Check out AlarmManager.
Alarms (based on the AlarmManager class) give you a way to perform time-based operations outside the lifetime of your application. For example, you could use an alarm to initiate a long-running operation, such as starting a service once a day to download a weather forecast.
Look up the AlarmManager API. I have used it to do things like what you are describing.
Note: 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. For normal timing operations (ticks, timeouts, etc) it is easier and much more efficient to use Handler.
http://developer.android.com/reference/android/app/AlarmManager.html

start service which repeat at top of every hour and fetch information at fixed time interval

i have setting repeated alarm manager to start service which fetch the location and send SMS but currently i am only writing time duration in file to check the alarm accuracy .
I find that the alarm manager not working fine , i set for one hours interval but it fired at 30 min. interval . I left it for a day and find that after 12'o clock the alarm accuracy is right. What happening ??
My Activity class which start alarm :
enter code here
public static final long ALARM_TRIGGER_AT_TIME = SystemClock.elapsedRealtime() + 20000;
public static final long ALARM_INTERVAL = 1000 * 60 * 60 ;
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
Intent myIntent = new Intent(AutoMainActivity.this, TrackerService.class);
pendingIntent = PendingIntent.getService(AutoMainActivity.this, 0, myIntent, 0);
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,ALARM_TRIGGER_AT_TIME, 1000 * 60 * 60,pendingIntent);
AND my service class :
TraceService :
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
//writing in file to view time
java.util.Date systemDates = Calendar.getInstance().getTime();
simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");
currentTime = simpleDateFormat.format(systemDates);
// create file and write current time
generateNoteOnSD("ONSTART"+currentTime+"\n","Onstart.txt");
}
After executing this apps at 3:18 PM time .The file created by service show the alarm time . Check this :
alarm manager time
ONSTART2013-05-13-15:18:26
ONSTART2013-05-13-15:21:58
ONSTART2013-05-13-15:54:21
ONSTART2013-05-13-16:18:25
ONSTART2013-05-13-17:18:26
ONSTART2013-05-13-17:49:21
ONSTART2013-05-13-18:18:25
ONSTART2013-05-13-19:18:28
ONSTART2013-05-13-20:10:51
ONSTART2013-05-13-20:18:29
ONSTART2013-05-13-20:48:49
ONSTART2013-05-13-21:18:30
ONSTART2013-05-13-21:58:58
ONSTART2013-05-13-22:18:38
ONSTART2013-05-13-22:56:00
ONSTART2013-05-13-23:18:43
ONSTART2013-05-13-23:48:49
ONSTART2013-05-14-00:18:44
ONSTART2013-05-14-01:18:45
ONSTART2013-05-14-02:18:45
ONSTART2013-05-14-03:18:45
ONSTART2013-05-14-04:18:45
ONSTART2013-05-14-05:18:44
ONSTART2013-05-14-06:18:44
ONSTART2013-05-14-07:18:44
You can check that when alarm manager start at 15:18 PM , it start again after 30 min. approx. But after 12'o clock it work fine !!! How to fix it. I need that alarm start every one hour not before that .
Try with AlarmManager.RTC_WAKEUP once instead of AlarmManager.ELAPSED_REALTIME_WAKEUP
There is an example in this : Alarm Manager Example
I suspect that you have multiple alarms pending. I would recommend that you clear out all of your alarms before you set this one.
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
// Cancel alarms
try {
alarmManager.cancel(intent);
} catch (Exception e) {
Log.e(TAG, "AlarmManager update was not canceled. " + e.toString());
}
}
(how to cancel alarms is answered well in this answer)
Not sure why everyone complicates this issue so much. I'm seeing it everywhere. Answers and answers about calculating the next hour.
There's absolutely no need to calculate anything. The the HOUR from the Calender and use that as the interval. The HOUR is called everytime the hour changes. That's all there really is to it.
Some devices may need a little tweaking to make sure the HOUR being called is not the same one for consecutive times. This is due to some devices calling the HOUR sometimes when the minute changes.

Categories

Resources