android - widget AlarmManager repeating too fast

2019-09-11 03:30发布

问题:

I have a widget which shows the data usage, for this I have created a PreferenceActivity where the user can choose from various update frequencies.. I get the chosen freq value from SharedPreferences and with that I start an alarm but I get weird result. Here is my AppWidgetProvider:

private static PendingIntent pendingIntent = null;
...
public void onReceive(Context context, Intent intent) {
    Log.d("TAG", "receive");
    super.onReceive(context, intent);

    if (CLOCK_WIDGET_UPDATE.equals(intent.getAction())) {
        ComponentName thisAppWidget = new ComponentName(context.getPackageName(), getClass().getName());
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
        int ids[] = appWidgetManager.getAppWidgetIds(thisAppWidget);
        for (int appWidgetID : ids) {
            updateAppWidget(context, appWidgetManager, appWidgetID);

        }
    }
}

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    Log.d("TAG", "update");
    super.onUpdate(context, appWidgetManager, appWidgetIds);

    for (int i = 0; i < appWidgetIds.length; i++) {
        int appWidgetId = appWidgetIds[i];

        updateAppWidget(context, appWidgetManager, appWidgetId);
    }
}

public static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {

    // starting timer
    AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    alarmManager.cancel(pendingIntent);

    Intent intent = new Intent(CLOCK_WIDGET_UPDATE);
    pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);


    SharedPreferences prefs = context.getSharedPreferences(Integer.toString(appWidgetId), Context.MODE_PRIVATE);
    int updateFrequencyMin = Integer.parseInt(prefs.getString(KEY_UPDATE_FREQ, DEFAULT_UPDATE_FREQ));
    Log.d("TAG", "Update freq: " + updateFrequencyMin);
    long updateFrequencyMillis = updateFrequencyMin * 60 * 1000;
    // alarmManager.cancel(pendingIntent); 
    alarmManager.setInexactRepeating(AlarmManager.RTC, System.currentTimeMillis(), updateFrequencyMillis,
            pendingIntent);

    ....
    appWidgetManager.updateAppWidget(appWidgetId, view);
}

public void onDisabled(Context context) {

    AlarmManager m = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    m.cancel(pendingIntent);
}

If I set the update frequency to 5 minutes with InexactRepeating, I get this log:

08-18 15:30:17.902: D/TAG(23624): receive
08-18 15:30:18.122: D/TAG(23624): receive
08-18 15:30:18.122: D/TAG(23624): update
08-18 15:30:18.122: D/TAG(23624): Update freq: 60
08-18 15:30:22.582: D/TAG(23624): receive
08-18 15:30:22.602: D/TAG(23624): Update freq: 60
08-18 15:30:33.272: D/TAG(23624): receive
08-18 15:30:33.282: D/TAG(23624): Update freq: 60
08-18 15:30:39.692: D/TAG(23624): receive 
08-18 15:30:39.692: D/TAG(23624): Update freq: 60
08-18 15:31:33.292: D/TAG(23624): receive <--- I have chosen the freq
08-18 15:31:33.292: D/TAG(23624): Update freq: 5
08-18 15:31:39.962: D/TAG(23624): receive
08-18 15:31:39.962: D/TAG(23624): Update freq: 5

I don't know why the onReceive and the onUpdate are called multiple times when I am on the configuration activity.

With the setRepeat method it is worse as you can see the timestamps:

08-18 15:38:59.992: D/TAG(24011): receive
08-18 15:39:00.242: D/TAG(24011): receive
08-18 15:39:00.242: D/TAG(24011): update
08-18 15:39:00.252: D/TAG(24011): Update freq: 60
08-18 15:39:00.442: D/TAG(24011): receive
08-18 15:39:00.442: D/TAG(24011): Update freq: 60
08-18 15:39:00.562: D/TAG(24011): receive
08-18 15:39:00.562: D/TAG(24011): Update freq: 60
08-18 15:39:00.642: D/TAG(24011): receive
08-18 15:39:00.642: D/TAG(24011): Update freq: 60
08-18 15:39:00.652: D/TAG(24011): receive
08-18 15:39:00.652: D/TAG(24011): Update freq: 60
08-18 15:39:00.662: D/TAG(24011): receive
08-18 15:39:00.662: D/TAG(24011): Update freq: 60

And finally, this is my preference activity:

public class DataStatWidgetConfigure extends PreferenceActivity {
    private int widgetId;

    @SuppressWarnings("deprecation")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Bundle extras = getIntent().getExtras();
        if (extras != null) {

            widgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,     AppWidgetManager.INVALID_APPWIDGET_ID);
            Log.d("meeegy", Integer.toString(widgetId));
            getPreferenceManager().setSharedPreferencesName(Integer.toString(widgetId));
            addPreferencesFromResource(R.xml.prefs);
        }

    }

    @Override
    public void onBackPressed() {
        Intent resultValue = new Intent();
        resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
        setResult(RESULT_OK, resultValue);
        finish();
    }
}

回答1:

From what I see in your code, you never cancel your previous alarms when you update your widget. So you keep adding more and more callback to AlarmManager. Try removing the previous call back and then add a new one



回答2:

The problem was with this:

 alarmManager.setInexactRepeating(AlarmManager.RTC, System.currentTimeMillis(), updateFrequencyMillis,
        pendingIntent);

The second parameter is when need to be called first, System.currentTimeMillis() means now, so right after this in OnReceive() called updateAppWidget() which called this setInexactRepeating() again immediately, and so on..

A solution:

alarmManager.setInexactRepeating(AlarmManager.RTC, System.currentTimeMillis() + updateFrequencyMillis,
            updateFrequencyMillis, pendingIntent);