Updating Android widget at midnight

How to update android widget every day at midnight ??? Below the solution is formed by looking at other Stack Overflow questions regarding this topic.

1) the schedule (context) is called when the widget is created in an activity that extends the AppWidgetProvider

    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        final int N = appWidgetIds.length;
        schedule(context);
    super.onUpdate(context, appWidgetManager, appWidgetIds);

}

      

2) The schedule method is to set a timer and an alarm so that the widget will update every day at midnight. however, it won'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);
    }

      

Solution doesn't work; and it is difficult to test because it can only be tested at midnight every day; hence generosity. I will hand it over to the first person who makes it work.

+3


source to share


2 answers


I created a date and time widget a while ago. Below is the implementation:

In the 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 class AlarmManagerBroadcasrReceiver:

@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 onwards, all setReapeating()

alarms are inaccurate. So, you can 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 complete implementation here.

+4


source


Rafiduzzman Sonnet's answer works (sort of), but it can be simplified. AppWidgetProvider

is already there BroadcastReceiver

, so we can direct the intent back to AppWidgetProvider

and override onReceive to handle it.

In your class extends 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 it AppWidgetManager.ACTION_APPWIDGET_UPDATE

doesn't update all widgets, even if you pass the full array of IDs as an additional one in AppWidgetManager.EXTRA_APPWIDGET_IDS

. It just updates the first widget it creates.

Here is a project I'm working on that implements a scheduled widget update like this.

+1


source







All Articles