Как заставить сервис перезапустить? - PullRequest
16 голосов
/ 31 августа 2011

У меня есть фоновая служба, которая иногда убивается ОС, когда у нее мало памяти.

  1. Как смоделировать это поведение, чтобы я мог его отладить?

Руководство разработчика просто говорит: «Если ваш сервис запущен, вы должны разработать его так, чтобы он корректно обрабатывал перезапуски системой. Если система убивает ваш сервис, она перезапускает его, как только становятся доступными ресурсы.снова».

Какова последовательность вызовов с момента, когда он завершается, до его перезапуска?

Что касается побочного (связанного) вопроса, что происходит с активно запущенным AsyncTask, запущенным в службе, когда службаубивается ОС, т. е. без service.onDestroy вызывается?Он продолжает работать или молча разорван вместе со службой?

Ответы [ 3 ]

8 голосов
/ 08 января 2012

В более новых версиях службы будут запускаться следующие события:

onCreate()

Вслед за ...

int onStartCommand(Intent intent, int flags, int startid)

Я знаю, что в комментариях выше вы упомянули об использовании этого, но стоит повторить: не используйте старое событие onStart (). onStartCommand - это новый способ ведения дел.

onCreate () можно использовать для создания любых объектов и т. Д., Но на самом деле используйте код вашей службы в onStartCommand ().

Когда закончите с onStartCommand (), вы должны вернуть результат. Использование «START_STICKY» сообщает ОС, что она может перезапуститься, если ей нужно убить ее. Использование «START_NOT_STICKY» говорит операционной системе, что не стоит пытаться перезапустить ее после того, как память снова станет доступной. Это означает, что ваше приложение должно будет вручную запустить службу снова. Есть и другие варианты - проверьте API документы.

Проверка этих флагов позволит вам понять, почему ваша служба запустилась - если ваше собственное приложение запустило его или операционная система запустила его для перезапуска. Вам нужно будет периодически сохранять состояние любых важных переменных, чтобы, если ОС перезапустила их, вы могли получить их - вы, вероятно, могли бы использовать личное хранилище SharedPreferences для их хранения. Определенно сохраняйте их в событии onDestroy, но не рассчитывайте на то, что они будут вызваны.

Кроме того, рекомендуется хранить поле startID в переменной и использовать его с stopSelfResult (startId), когда служба завершена.

Имейте в виду, что если ваша служба уничтожена ОС, у вас может не быть возможности хранить какие-либо переменные. Вы должны иметь возможность видеть, соответствует ли ваше состояние ожидаемому при перезапуске с помощью ОС и если не просто сбросить все или изящно умереть, может быть.

Что касается отладки, задумывались ли вы над написанием другого приложения, которое только всасывает память в Activity, чтобы вызвать состояние нехватки памяти? Верхний уровень активности должен получить преимущество над памятью и заставить службу умирать.

Дополнительные потоки, запущенные в службе, все еще являются частью того же процесса приложения, , поэтому они будут уничтожены вместе со службой (и остальной частью приложения). Вы можете убедиться в этом, добавив обычный журнал. заявления внутри потоков, а затем убить службу.

Что-то еще, что может быть полезно для вас, проверяет, работает ли ваш сервис изнутри вашего приложения. Вот функция для этого:

// Determine if one of my services is currently running
public static boolean isMyServiceRunning(Context context, String servicename) {
    ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (servicename.equals(service.service.getClassName())) {
            return true;
        }
    }
    return false;
}
3 голосов
/ 01 сентября 2011

Если это локальная служба (по умолчанию), а не удаленная служба, то она работает в том же процессе, что и ваше приложение.Это означает, что вы можете эмулировать убийство, просто убивая процесс вашего приложения.Вы можете сделать это, используя ddms, например, в eclipse или из командной строки, или даже с вашего телефона (настройки -> приложения).

0 голосов
/ 23 апреля 2019

Котлинская версия Тони Маро ответ:

@Suppress("DEPRECATION")
fun <T> Context.isServiceRunning(service: Class<T>): Boolean {
    return (getSystemService(ACTIVITY_SERVICE) as ActivityManager)
        .getRunningServices(Integer.MAX_VALUE)
        .any { it.service.className == service.name }
}
...