views:

84

answers:

1

Hi

I've an IntentService which updates an AppWidget. That Service starts every time the AppWidget is being placed on the Screen or when the AlarmManager /ContentObserver / OnChangeListener get called. It stops itself after updating the widget.

UpdateService.java:
@Override
public void onCreate() {
    contentObserver = new CustomContentObserver();
    registerContentObserver(contentObserver);

    /* Am I registering several instances here or is this fine? */

    onChangeListener = new CustomSharedPreferencesOnChangeListener();
    sharedPreferences.registerOnSharedPreferenceChangeListener(onChangeListener);

    Intent updateIntent = new Intent(this, UpdateService.class);
    pendingIntent = PendingIntent.getService(this, 0, updateIntent, 0);
    alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
}

@Override
public void onStart(Intent intent, int startId) {
    if(AppWidget.DISABLE.equals(intent.getAction())) {
        unregisterContentObserver(contentObserver); 
        sharedPreferences.unregisterOnSharedPreferenceChangeListener(onChangeListener);
        alarmManager.cancel(pendingIntent);
    } else {
        /* Scheduling next update */
        alarmManager.set(AlarmManager.RTC_WAKEUP, nextUpdateTime, pendingIntent);

        /* Updating the Widget ... */
        updateWidget();

        /* Stopping the Service */
        stopSelf();
    }
}

The service shouldn't start when there is no widget to update, so I have to unregister the listener and observer and cancel the pending intent.

I am wondering what the best way is to clean up the resources? Starting the service to stop it seems a bit awkward to me.

AppWidget.java:
@Override
public void onDisabled(Context context) {
    Intent intent = new Intent(context, UpdateService.class);
    intent.setAction(DISABLE);
    context.startService(intent);
    context.stopService(intent);
    super.onDisabled(context);
}

I am also wondering about the costs of starting and stopping a service. Would it be better to let the Service run all the time and clean up in onDestroy() when the last widget is removed?

+1  A: 

Never register a listener in an IntentService, just as you never register a listener in a manifest-registered BroadcastReceiver. These are supposed to be short-lived objects. Your listeners are keeping your defunct IntentService in memory and are leaking memory along the way.

Would it be better to let the Service run all the time and clean up in onDestroy() when the last widget is removed?

User get very irritated when applications keep services running all the time, unless they clearly understand the benefit. I would avoid this.

CommonsWare
Thanks for your quick response. So is it better to register the ChangeListener when the PreferenceScreen opens to send an updateIntent every time preferences change?Where would you register the ContentObserver?
@konradf: "So is it better to register the ChangeListener when the PreferenceScreen opens to send an updateIntent every time preferences change?" -- that should work AFAIK. "Where would you register the ContentObserver?" -- I wouldn't. It doesn't do you any good. Update the widget per your timer -- you do not need a `ContentObserver` for that. If you want, send an update to the widget from whatever is updating the content that you are trying to observe.
CommonsWare