I'm trying to update fragment on clock time, say for example 8PM, with below logic. Unfortunately, it doesn't update the fragment. Any help/reference would be appreciated.
What I did:
registered an AlarmManager in app's Application class as below:
alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent().setAction(AppConstants.INTENT_ACTION_UPDATE_DASHBOARD);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
// Set the alarm to start at Consulting start time
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
alarmMgr.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), alarmIntent);
Listens for AlarmManager in Fragment as below:
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(mDashboardUpdateReceiver, new IntentFilter
(AppConstants.INTENT_ACTION_UPDATE_DASHBOARD));
and performs actions if broadcast receives:
private BroadcastReceiver mDashboardUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Dashboard updating...");
updateCounters();
}
First, a PendingIntent does not trigger a local broadcast. You cannot use LocalBroadcastManager here.
Second, using AlarmManager to update a UI is rather odd. If your UI exists, you have a process running, so you could use something in-process (e.g., ScheduledExecutorService) rather than fussing with AlarmManager.
Third, you are not taking into account that set(Calendar.HOUR_OF_DAY, hour) and calendar.set(Calendar.MINUTE, minute) might change the Calendar to be in the past. Imagine if you execute your first code snippet at 23:00, with hour set to be 22 and minute set to be 0. The Calendar object that you create will be for today, but for 22:00 today, which was an hour before now (23:00). You need to check the Calendar, see if it is in the past, and if so, add() a day or otherwise adjust it to some future time.
Related
Hello i want to make a background service to update the data of my app and repeat it once a day, also i want the service to start onboot. I have the following code:
public class OnBoot extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Create Intent
context.startService(new Intent(context, BackgroundServiceHandler.class));
}
}
I have a settings menu so the user can choose the hour of the repeating alarm.
How can i reset the time of the alarmmanager? Where i have to put the code of the alarm manager? Do i have to use service or intentservice? How to check if service is running?
Alarm manager code:
Intent intent = new Intent(MainActivity.this, AlarmService.class);
intent.putExtra("i", 3);
PendingIntent pi = PendingIntent.getService(MainActivity.this, 9, intent, 0);
// every day at 9 am
Calendar calendar = Calendar.getInstance();
// if it's after or equal 9 am schedule for next day
if (Calendar.getInstance().get(Calendar.HOUR_OF_DAY) >= 9) {
calendar.add(Calendar.DAY_OF_YEAR, 1); // add, not set!
}
calendar.set(Calendar.HOUR_OF_DAY, 9);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setInexactRepeating(AlarmManager.RTC, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pi);
How can i reset the time of the alarmmanager?
How to edit/reset Alarm Manager?
Where i have to put the code of the alarm manager?
For example you can place that code in static method and call it from place where user set time and from OnBootReceiver. How to implement class which will receive event OnBoot please check that answer.
Do i have to use service or intentservice?
Service vs IntentService
How to check if service is running?
Check if service is running on Android?
I have this static helper function, to set a daily-repeating alarm:
public static void setAlarm(Context context, int hh, int mm)
{
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, hh);
calendar.set(Calendar.MINUTE, mm);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intentAlarm = new Intent(context, AlarmReciever.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intentAlarm, 0);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, alarmIntent);
}
I have three places where this helper function is called:
When device boots up, I want to re-register the alarm:
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
setAlarm(context, 7, 00);
}
}
In one of my activities, call it ActivityA:
AlarmReciever.setAlarm(ActivityA.this, 7, 00);
In another activity, call it ActivityB:
AlarmReciever.setAlarm(ActivityB.this, 7, 00);
Questions:
What would happen if all three kinds of setAlarm() are called? I'm concerned that they don't have the same context. Would android know they are the same PendingIntent and only fire once? I want it to only fire once at 7 am.
What if I press setAlarm button in ActivityA a few times so the same alarm is set with the same context and intent, when 7 am comes, how many would fire?
Say it fired at 7 am this morning and now it's 2 pm in the afternoon. I now press the button in ActivityA. The alarm would fire instantly (tested), because 7 am is a "past time". But before adding the new alarm, shouldn't the system check existing ones, and realize this is a repeating intent, and one has been fired at 7 am already? In my opinion it should ignore my setAlarm() requested at 2 pm.
For what it's worth, I did experiments and I'm posting the results here in case anyone else wonders:
As long as the PendingIntent is identical, android will only fire the alarm once. You may set the alarm however many times you want, from whatever activities/classes you want.
One.
The new alarm will just trigger right way (because 7 am is a "past time"). You can write code to record the last fired date/hour (e.g. use SharedPreferences), and do some logic there, or depends on your situation, you may want to schedule the alarm to fire at 7 am the next day (do a plus one day on the Calendar object).
I've an intent that starts a new class at fixed time (and date). This intents start at fixed date BUT also at every reboot (also after the date and time are are in the past). In my code the New.class starts at 26/12/12 - 21.30 but if I reboot emulator after that time, New.class starts automatically. Why? Thanks!
PS: this code is within an Autostart class (public void onReceive(Context context, Intent intent) {)
Calendar cal = Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault());
cal.set(Calendar.DATE,26);
cal.set(Calendar.MONTH,Calendar.DECEMBER);
cal.set(Calendar.YEAR,2012);
cal.set(Calendar.HOUR_OF_DAY, 21);
cal.set(Calendar.MINUTE, 30);
cal.set(Calendar.SECOND, 00);
Intent intent3 = new Intent(context, New.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,intent3, 0);
alarmManager.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pendingIntent);
That's by design. See the documentation of the set() method:
"If the time occurs in the past, the alarm will be triggered immediately."
If you do not want this to happen, you shouldn't schedule the Alarm. That is, you should check yourself whether to call set() within the BroadcastReceiver.
I want the following:
The AlarmManager sends a daily intent to my AppWidgetProvider at midnight EXACTLY.
The Alarm must wake up the device.
Here is how I did it:
In my AppWidgetProvider subclass:
#Override
public void onEnabled(Context context) {
super.onEnabled(context);
Log.d(LOG_TAG, "Widget Provider enabled. Starting timer");
//Setting the Calender object to midnight time.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 0);
calendar.add(Calendar.MINUTE, 0);
calendar.add(Calendar.HOUR, 0);
//The fired Intent
Intent intent = new Intent(CLOCK_WIDGET_UPDATE); //custom intent name
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), 1000*60*60*24, pendingIntent);
}
Although I think I did it right, this code doesn't work!
To test it, I changed 1000*60*60*24 with 10000 (10 sec) and updated a textView in the widget with random number. The random number never changed.
Any help will be appreciated !
I finally found the problem !
It seems that I need to set the AM_PM value too. When I print the calender using getTime().toLocaleString(), it was set to the next day but 12 hours later (12:00:00 PM).
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.HOUR, 0);
calendar.set(Calendar.AM_PM, Calendar.AM);
calendar.add(Calendar.DAY_OF_MONTH, 1);
This is a perfect setup for the Calender instance that will set the alarm to the next day at midnight (i.e. the nearest midnight). You just pass it to the setRepeating() method.
Thanks #CommonsWare
First, what you want is not strictly possible. Android is not a RTOS; you may not get control "at midnight EXACTLY"
Second, your Calendar object represents a time in the past (unless it happens to be midnight at the time you are executing that code, in which case it represents the present). Try a start time in the future.
I am developing an Android app which must perform 2 periodic tasks in background:
download files from server every 24 hours.
perform file operations each week on phone sd card.
How do i do this?
Firstly you need to use AlarmManager. When the registered alarm e.g. 24 hours case, will trigger, you can call service from the broadcast receiver of AlarmManager. You need to study a bit about AlarmManager if you don't already know. For further help you can get some idea from code below:
Calendar cur_cal = new GregorianCalendar();
cur_cal.setTimeInMillis(System.currentTimeMillis());
Calendar cal = new GregorianCalendar();
cal.set(Calendar.DAY_OF_YEAR, cal.get(Calendar.DAY_OF_YEAR) + 1); //+1 For Next day (24 hours or so...)
cal.set(Calendar.HOUR_OF_DAY, hour);
cal.set(Calendar.MINUTE, minute);
cal.set(Calendar.SECOND, cur_cal.get(Calendar.SECOND));
cal.set(Calendar.MILLISECOND, cur_cal.get(Calendar.MILLISECOND));
cal.set(Calendar.DATE, cur_cal.get(Calendar.DATE));
cal.set(Calendar.MONTH, cur_cal.get(Calendar.MONTH));
AlarmManager am = (AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getApplicationContext(), AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, intent, PendingIntent.FLAG_ONE_SHOT);
am.cancel(pendingIntent);
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pendingIntent);
Here is how you can set your Alarm. Now when Alarm will be triggered, you will call your service like this:
public class AlarmReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context arg0, Intent arg1)
{
// Call you service or any task here
}
}
Last thing, don't forget to mention your broadcast receiver and service in AndroidManifest.xml
<receiver android:name=".AlarmReceiver">
</receiver>
<service android:name=".MyService"/>
Here's what official android docs says about AlarmManager
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.
Handler documentation.