Android: сохранение фоновой службы (предотвращение процесса смерти)

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

public class SleepAccelerometerService extends Service implements SensorEventListener

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

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/

Ответ 1

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

В документации указано следующее:

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

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

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

Ответ 2

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

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

Ответ 3

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

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

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

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

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

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

Ответ 4

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.

Ответ 5

У меня была аналогичная проблема. На некоторых устройствах через некоторое время 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 necessary
            setServiceWatchdogTimer(true, 60000*5); // restart the watchdogtimer
        }
    }
}

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

Ответ 6

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

Ответ 7

Я работаю над приложением и сталкивается с проблемой убийства моего сервиса при убийстве приложения. Я исследовал 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);

    }
}

прыгает, что это может помочь!!!!