Жизненный цикл службы и лучший способ отменить регистрацию слушателей

У меня есть IntentService, который обновляет AppWidget. Эта служба запускается каждый раз, когда AppWidget помещается на экран или когда вызывается AlarmManager/ContentObserver/OnChangeListener. Он останавливается после обновления виджета.

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();
    }
}

Служба не должна запускаться, когда нет виджета для обновления, поэтому мне нужно отменить регистрацию слушателя и наблюдателя и отменить ожидающее намерение.

Мне интересно, как лучше всего очистить ресурсы? Запуск службы для остановки кажется мне немного неудобным.

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);
}

Меня также интересуют затраты на запуск и останов службы. Было бы лучше, чтобы Служба работала все время и очищалась в onDestroy() при удалении последнего виджета?


person Konrd    schedule 26.08.2010    source источник


Ответы (1)


Никогда не регистрируйте слушателя в IntentService, точно так же, как вы никогда не регистрируете слушателя в BroadcastReceiver, зарегистрированном в манифесте. Предполагается, что это недолговечные объекты. Ваши слушатели хранят ваш несуществующий IntentService в памяти и по пути утекают память.

Было бы лучше, чтобы Служба работала все время и очищалась в onDestroy() при удалении последнего виджета?

Пользователей очень раздражает, когда приложения поддерживают работу служб все время, если только они не понимают явной выгоды. Я бы избегал этого.

person CommonsWare    schedule 26.08.2010
comment
Спасибо за ваш быстрый ответ. Так что лучше регистрировать ChangeListener, когда PreferenceScreen открывается, чтобы отправлять updateIntent каждый раз, когда меняются настройки? Где бы вы зарегистрировали ContentObserver? - person Konrd; 26.08.2010
comment
@konradf: Так что лучше регистрировать ChangeListener, когда PreferenceScreen открывается, чтобы отправлять updateIntent каждый раз, когда меняются настройки? - это должно работать, насколько я знаю. Где бы вы зарегистрировали ContentObserver? -- Я бы не стал. Это не идет вам на пользу. Обновите виджет по вашему таймеру — для этого вам не нужен ContentObserver. Если вы хотите, отправьте обновление виджету от того, что обновляет контент, который вы пытаетесь наблюдать. - person CommonsWare; 27.08.2010
comment
@CommonsWare Что же тогда было бы лучшим способом управления фоновым наблюдателем, если не внутри фоновой службы? Я хочу, чтобы наблюдатель был жив, пока жива система. - person Olayinka; 16.04.2015
comment
@Olayinka: я не знаю, о каком наблюдателе вы говорите. Обычно вы хотите, чтобы вас двигали события (трансляции, AlarmManager и т. д.). Я хочу, чтобы наблюдатель был жив до тех пор, пока жива система — затем создайте свое собственное устройство или собственное ПЗУ, поскольку пользователи Android могут избавиться от вашего сервиса, когда захотят. Вам нужно будет создать стандартный демон Linux, чтобы пользователи не могли управлять им напрямую. Вы можете предпринять шаги (службы переднего плана, START_STICKY и т. д.), чтобы попытаться жить долго, но вы не можете жить вечно. - person CommonsWare; 16.04.2015
comment
@CommonsWare Конечно, я знаю о способностях пользователя и системы отключить службу, но тогда я всегда могу перезапустить ее с помощью Alarm, Boot, START_STICKY, но проблема в том, что этой службе необходимо зарегистрировать наблюдателя. - person Olayinka; 16.04.2015
comment
@Olayinka: Опять же, я не знаю, о каком наблюдателе вы говорите и какое это имеет отношение к этому ответу. Мои заметки о слушателях относятся к IntentService, а не Service. - person CommonsWare; 16.04.2015
comment
@CommonsWare Я использую IntentService и ContactObserver. - person Olayinka; 16.04.2015
comment
@Olayinka: Поскольку в Android SDK нет ContactObserver, я не знаю, о чем вы говорите. Но ваш процесс может прекратиться после того, как IntentService закончит onHandleIntent(), и поэтому, если вам нужен надежный сервис, используйте Service и разветвите свои собственные потоки. - person CommonsWare; 16.04.2015
comment
@CommonsWare Это была опечатка, я имел в виду ContentObserver, но все равно спасибо. - person Olayinka; 16.04.2015
comment
@Olayinka: Да, для надежного ContentObserver используйте Service и разветвите свои собственные потоки. Недостатком ContentObserver является то, что, насколько я знаю, он выдает результаты только в основном потоке приложения, поэтому вам нужно определить, как лучше всего перенести значительную работу из этого потока в фоновый поток. - person CommonsWare; 16.04.2015
comment
@CommonsWare Спасибо за ваше время. Я буду использовать этот подход методом проб и ошибок и посмотрю, смогу ли я получить хороший результат. - person Olayinka; 17.04.2015