How to update Android widget everyday at midnight?? Below solution is formed by looking at other questions in stack overflow regarding to this topic.
1) schedule(context) is called when widget is created in the activity that extends AppWidgetProvider
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final int N = appWidgetIds.length;
schedule(context);
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
2) Schedule method should set a timer and alarm so that the widget gets updated at everyday at midnight. however this doesn't work.
protected void schedule(Context context) {
final Intent i = new Intent(context, CalendarWidget.class);
service = PendingIntent.getService(context, 0, i, PendingIntent.FLAG_CANCEL_CURRENT);
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);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
//This doesn't work
// alarmManager.set(AlarmManager.RTC, calendar.getTimeInMillis(), service);
//This doesn't work either.
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, service);
}
The solution doesn't work; and it is hard to test it because it can be tested only at midnight everyday; hence, the bounty. I will awarded it to the first person that makes it work.
Any call to updateWidgets() will cause all instances of our widget to be updated. Of course, be careful not to update to often - widget updates use battery power. Bear in mind that the broadcast is received by ALL widget providers, and its our special keys that ensure it is only our widgets that actually update.
Full update: Call AppWidgetManager. updateAppWidget(int, android. widget. RemoteViews) to fully update the widget.
denvercoder9's answer works (sort of) but it could be simplified. An AppWidgetProvider
is already a BroadcastReceiver
, so we can actually direct the intent back on the AppWidgetProvider
, and override onReceive to handle it.
In your class extending AppWidgetProvider
:
private static final String ACTION_SCHEDULED_UPDATE = "your.package.name.SCHEDULED_UPDATE";
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_SCHEDULED_UPDATE)) {
AppWidgetManager manager = AppWidgetManager.getInstance(context);
int[] ids = manager.getAppWidgetIds(new ComponentName(context, AppWidget.class));
onUpdate(context, manager, ids);
}
super.onReceive(context, intent);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// Do your updates...
_scheduleNextUpdate(context);
}
private static void _scheduleNextUpdate(Context context) {
AlarmManager alarmManager =
(AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// Substitute AppWidget for whatever you named your AppWidgetProvider subclass
Intent intent = new Intent(context, AppWidget.class);
intent.setAction(ACTION_SCHEDULED_UPDATE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
// Get a calendar instance for midnight tomorrow.
Calendar midnight = Calendar.getInstance();
midnight.set(Calendar.HOUR_OF_DAY, 0);
midnight.set(Calendar.MINUTE, 0);
// Schedule one second after midnight, to be sure we are in the right day next time this
// method is called. Otherwise, we risk calling onUpdate multiple times within a few
// milliseconds
midnight.set(Calendar.SECOND, 1);
midnight.set(Calendar.MILLISECOND, 0);
midnight.add(Calendar.DAY_OF_YEAR, 1);
// For API 19 and later, set may fire the intent a little later to save battery,
// setExact ensures the intent goes off exactly at midnight.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
alarmManager.set(AlarmManager.RTC_WAKEUP, midnight.getTimeInMillis(), pendingIntent);
} else {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, midnight.getTimeInMillis(), pendingIntent);
}
}
We need a custom intent action, because AppWidgetManager.ACTION_APPWIDGET_UPDATE
doesn't update all widgets, even if you pass in the full array of ids as an extra under AppWidgetManager.EXTRA_APPWIDGET_IDS
. It just updates the first widget created.
Here is a project I'm working on that implements a scheduled widget update similar to this.
I created a date and time widget a while back. Below is the implementation:
In AppWidgetProvider class:
private boolean first_run = true;
public AlarmManager am;
public PendingIntent pi;
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
first_run = context.getSharedPreferences("mywidet", MODE_PRIVATE).getBoolean("first_run", true);
if(first_run) {
am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);
pi = PendingIntent.getBroadcast(context, 0, intent, 0);
long current = System.currentTimeMillis();
LocalTime localTime = LocalTime.now();
long triggerOffset = (24*60*60 - localTime.getHour()*60*60 - localTime.getMinute()*60 - localTime.getSecond())*1000;
am.setRepeating(AlarmManager.RTC_WAKEUP, current + triggerOffset, 86400000, pi);
SharedPreferences.Editor editor = context.getSharedPreferences("mywidet", MODE_PRIVATE).edit();
editor.putBoolean("first_run", false);
editor.apply();
}
for (int appWidgetId : appWidgetIds) {
appWidgetManager.updateAppWidget(appWidgetId, remoteView);
}
}
in AlarmManagerBroadcasrReceiver class:
@Override
public void onReceive(Context context, Intent intent) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "YOUR TAG");
//Acquire the lock
wl.acquire();
Log.d("widget", "in alarm manager. static method will come next");
ComponentName thisWidget = new ComponentName(context, NewAppWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(context);
manager.updateAppWidget(thisWidget, remoteViews);
//Release the lock
wl.release();
}
EDIT 1
From API 19 onward all setReapeating()
alarms are inexact. So, one might want to do the following:
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, nexMin.getTimeInMillis()-current.getTimeInMillis(), 60000, pendingIntent);
} else {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, nexMin.getTimeInMillis() - current.getTimeInMillis(), pendingIntent);
}
You can find the full implementation here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With