Android: поддержка фонового сервиса (предотвращение смерти процесса) - PullRequest
51 голосов
/ 04 октября 2010

У меня есть служба, которая определяется как:

public class SleepAccelerometerService extends Service implements SensorEventListener

По сути, я делаю приложение, которое отслеживает активность акселерометра по разным причинам, пока пользователь спит со своим телефоном / устройством на кровати.Это длительный сервис, который НЕ ДОЛЖЕН быть убит ночью.В зависимости от того, сколько фоновых приложений и периодических процессов происходит в течение ночи, android иногда убивает мой процесс, тем самым заканчивая мой сервис.Пример:

10-04 03:27:41.673: INFO/ActivityManager(1269): Process com.androsz.electricsleep (pid 16223) has died.
10-04 03:27:41.681: INFO/WindowManager(1269): WIN DEATH: Window{45509f98 com.androsz.electricsleep/com.androsz.electricsleep.ui.SleepActivity paused=false}

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

Есть какие-нибудь советы?Исходный код здесь: http://code.google.com/p/electricsleep/

Ответы [ 7 ]

72 голосов
/ 04 октября 2010

Для Android 2.0 или более поздней версии вы можете использовать метод startForeground() , чтобы запустить службу на переднем плане.

Документация гласит следующее :

Запущенная служба может использовать API startForeground(int, Notification), чтобы перевести службу в состояние переднего плана, где система считает, что это то, о чем пользователь активно осведомлен, и, следовательно, не является кандидатом на убийство при нехватке памяти. (По-прежнему теоретически возможно уничтожение службы под сильным давлением памяти со стороны текущего приложения переднего плана, но на практике это не должно вызывать беспокойства.)

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

Вам нужно будет указать Notification для метода, который отображается на панели уведомлений в разделе «Текущая».

16 голосов
/ 27 января 2011

Когда вы связываете свою службу с действием с помощью BIND_AUTO_CREATE, ваша служба уничтожается сразу после того, как ваша активность уничтожена и не связана.Это не зависит от того, как вы реализовали свой метод unBind Служб, он все равно будет уничтожен.

Другой способ - запустить службу с помощью метода startService из вашей деятельности.Таким образом, даже если ваша активность будет уничтожена, ваш сервис не будет разрушен или даже приостановлен, но вы должны будете приостановить / уничтожить его самостоятельно с помощью stopSelf / stopService, когда это необходимо.

11 голосов
/ 04 марта 2014

Как Дейв уже указал , вы можете запустить свой Service с приоритетом переднего плана. Но эту практику следует использовать только тогда, когда это абсолютно необходимо, т. Е. Когда это приведет к плохому пользовательскому опыту, если Сервис будет убит Android. Вот что на самом деле означает «передний план»: ваше приложение каким-то образом находится на переднем плане, и пользователь сразу же заметит его, если его убьют (например, потому что он воспроизвел песню или видео).

В большинстве случаев запрос приоритетного приоритета для вашего Сервиса является контрпродуктивным!

Почему это? Когда Android решает убить Service, это происходит потому, что ему не хватает ресурсов (обычно ОЗУ). Основываясь на различных классах приоритетов, Android решает, какие запущенные процессы, включая сервисы, завершить, чтобы освободить ресурсы. Это здоровый процесс, который вы хотите осуществить, чтобы у пользователя было приятное впечатление. Если вы запросите приоритет переднего плана, без веской причины, просто чтобы убить ваш сервис, это, скорее всего, вызовет плохой пользовательский опыт. Или вы можете гарантировать, что ваш сервис останется в пределах минимального потребления ресурсов и не будет иметь утечек памяти? 1

Android предоставляет липкие сервисы , чтобы помечать сервисы, которые должны быть перезапущены после некоторого льготного периода, если они были убиты. Этот перезапуск обычно происходит в течение нескольких секунд.

Изображение, которое вы хотите написать XMPP-клиент для Android. Стоит ли запрашивать приоритет переднего плана для Service, который содержит ваше XMPP-соединение? Определенно нет, нет абсолютно никаких причин для этого. Но вы хотите использовать START_STICKY в качестве флага возврата для метода onStartCommand вашего сервиса. Так что ваш сервис останавливается, когда возникает нехватка ресурсов, и перезапускается, когда ситуация возвращается к нормальной.

1 : Я почти уверен, что многие приложения для Android имеют утечки памяти. Это то, о чем не заботится обычный (настольный) программист.

5 голосов
/ 22 сентября 2015

У меня была похожая проблема. На некоторых устройствах через некоторое время Android убивает мой сервис и даже startForeground () не помогает. И мой клиент не любит эту проблему. Мое решение - использовать класс AlarmManager , чтобы убедиться, что служба работает, когда это необходимо. Я использую AlarmManager для создания своего рода сторожевого таймера. Время от времени он проверяет, должна ли служба работать, и перезапускает ее. Также я использую SharedPreferences , чтобы сохранить флаг, должен ли сервис быть запущен.

Создание / удаление моего сторожевого таймера:

void setServiceWatchdogTimer(boolean set, int timeout)
{
    Intent intent;
    PendingIntent alarmIntent;
    intent = new Intent(); // forms and creates appropriate Intent and pass it to AlarmManager
    intent.setAction(ACTION_WATCHDOG_OF_SERVICE);
    intent.setClass(this, WatchDogServiceReceiver.class);
    alarmIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    AlarmManager am=(AlarmManager)getSystemService(Context.ALARM_SERVICE);
    if(set)
        am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + timeout, alarmIntent);
    else
        am.cancel(alarmIntent);
}

Получение и обработка намерения от сторожевого таймера:

/** this class processes the intent and
 *  checks whether the service should be running
 */
public static class WatchDogServiceReceiver extends BroadcastReceiver
{
    @Override
    public void onReceive(Context context, Intent intent)
    {

        if(intent.getAction().equals(ACTION_WATCHDOG_OF_SERVICE))
        {
            // check your flag and 
            // restart your service if it's necessary
            setServiceWatchdogTimer(true, 60000*5); // restart the watchdogtimer
        }
    }
}

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

4 голосов
/ 21 января 2014

http://developer.android.com/reference/android/content/Context.html#BIND_ABOVE_CLIENT

public static final int BIND_ABOVE_CLIENT - добавлено в уровень API 14

Флаг для bindService(Intent, ServiceConnection, int): указывает, что привязка клиентского приложения к этой службе считает службу более важной, чем само приложение. Если установлено, платформа будет пытаться убить нехватку памяти из приложения, прежде чем оно убьет службу, к которой она привязана, хотя это не гарантируется.

Другие флаги той же группы: BIND_ADJUST_WITH_ACTIVITY, BIND_AUTO_CREATE, BIND_IMPORTANT, BIND_NOT_FOREGROUND, BIND_WAIVE_PRIORITY.

Обратите внимание, что значение BIND_AUTO_CREATE изменилось в ICS, и старых приложений, которые не указывают BIND_AUTO_CREATE , для них автоматически будут установлены флаги BIND_WAIVE_PRIORITY и BIND_ADJUST_WITH_ACTIVITY .

2 голосов
/ 24 июня 2016

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

public class UpdateLocationAndPrayerTimes extends Service {

 Context context;
@Override
public void onCreate() {
    super.onCreate();
    context = this;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    StartForground();
    return START_STICKY;
}

@Override
public void onDestroy() {


    super.onDestroy();
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}


private void StartForground() {
    LocationChangeDetector locationChangeDetector = new LocationChangeDetector(context);
    locationChangeDetector.getLatAndLong();
    Notification notification = new NotificationCompat.Builder(this)
            .setOngoing(false)
            .setSmallIcon(android.R.color.transparent)

            //.setSmallIcon(R.drawable.picture)
            .build();
    startForeground(101,  notification);

    }
}

хмель, что может помочь !!!!

2 голосов
/ 04 октября 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...