2010-10-04 26 views
49

he un servicio que se define como:Android: mantener un servicio en segundo plano vivos (prevención de la muerte proceso)

public class SleepAccelerometerService extends Service implements SensorEventListener 

Esencialmente, estoy haciendo una aplicación que controla la actividad del acelerómetro, por diversas razones, mientras el usuario duerme con su teléfono/dispositivo en la cama. Este es un servicio de larga duración que NO DEBE matarse durante la noche. Dependiendo de cuántas aplicaciones en segundo plano y procesos periódicos se producen durante la noche, a veces Android mata a mi proceso, lo que termina mi servicio. Ejemplo:

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} 

no quiero obligar al usuario a tener 'SleepActivity' o alguna otra actividad en mi aplicación como el primer plano. No puedo hacer que mi servicio se ejecute periódicamente, ya que está interceptando constantemente OnSensorChanged.

¿Algún consejo? el código fuente está aquí: http://code.google.com/p/electricsleep/

Respuesta

70

Para Android 2.0 o posterior, puede usar el startForeground() method para iniciar su Servicio en primer plano.

El documentation says the following:

Un comenzaron servicio puede utilizar la API de startForeground(int, Notification) para poner el servicio en un estado plano, donde el sistema considera que es algo que el usuario es activamente consciente de y por lo tanto no es un candidato para matando cuando falta memoria. (Todavía es teóricamente posible que el servicio sea eliminado bajo la presión de memoria extrema de la aplicación de primer plano actual, pero en la práctica esto no debería ser una preocupación).

El propósito principal es matar el servicio. perjudicial para el usuario, por ejemplo matar un servicio de reproducción de música detendría la reproducción de música.

Deberá proporcionar un Notification al método que se muestra en la Barra de notificaciones en la sección En curso.

+2

Gracias. Ya había oído hablar de startForeground antes, pero no esperaba que startForeground fuera un método en Service (aunque tiene sentido que esté allí ahora que lo pienso). –

+4

Tengo una consulta. ¿Qué pasa si no quiero mostrar ninguna notificación pero aún quiero usar el método startForeground()? –

+4

@farhanahaque - No puedes. Solo debe utilizar 'startForeground()' para ver si la eliminación del servicio podría ser perjudicial para el usuario, por ejemplo, haciendo algo como tocar música. Siendo este el caso, debe ser algo que el usuario conoce y por lo tanto tiene visibilidad a través de una Notificación. 'startForeground()' no pretende ser una alternativa para responder adecuadamente a los eventos del ciclo de vida. –

2

Mantenga la huella de su servicio pequeña, esto reduce la probabilidad de que Android cierre su aplicación. No puede evitar que lo maten porque, si pudiera, la gente podría crear fácilmente spyware persistente

+1

O podría iniciar otro servicio y permitir que se miren unos a otros para asegurarse de que mueran y luego el otro lo reinicia. Feo pero posiblemente efectivo – BeRecursive

+2

Necesito optimizar la memoria que consume mi servicio (voy a volcar los datos en un SQLite db en el archivo), especialmente porque crece inherentemente con el tiempo, sin embargo, me pregunto por qué mi el servicio se está eliminando mientras otros servicios continúan ejecutándose. Sé que hay un sistema de prioridad integrado en los servicios: ¿cómo puedo aumentar la prioridad de mi servicio? –

+1

@Jon - Si se cancela su servicio, con el tiempo se reiniciará. Sé que dijiste que no querías, pero la única forma de aumentar la prioridad es convencer al sistema operativo de que el servicio está actualmente activo para el usuario (en primer plano, usando startForeground (int, Notificación)) – BeRecursive

16

Cuando vincula su Servicio a la actividad con BIND_AUTO_CREATE, su servicio se destruye justo después de que su actividad se destruye y desata. No depende de cómo hayas implementado el método de desvinculación de servicios, aún se eliminará.

La otra forma es comenzar su Servicio con el método startService de su Actividad. De esta forma, incluso si se destruye tu actividad, tu servicio no se destruirá o incluso se detendrá, pero tienes que pausar/destruirlo por ti mismo con stopSelf/stopService cuando corresponda.

4

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

público static final int BIND_ABOVE_CLIENT - Añadido en el nivel API

Bandera de bindService(Intent, ServiceConnection, int): indica que la aplicación cliente se une a este servicio considera que el servicio sea más importante que la aplicación en sí. Cuando se establezca, la plataforma intentará que el asesino sin memoria mate la aplicación antes de que mate el servicio al que está destinada, aunque no se garantiza que sea así.

Otros indicadores del mismo grupo son: BIND_ADJUST_WITH_ACTIVITY, BIND_AUTO_CREATE, BIND_IMPORTANT, BIND_NOT_FOREGROUND, BIND_WAIVE_PRIORITY.

Tenga en cuenta que el significado de BIND_AUTO_CREATE ha cambiado en el ICS, y aplicaciones antiguas que no especifiqueBIND_AUTO_CREATEtendrá automáticamente las marcas deBIND_WAIVE_PRIORITY y BIND_ADJUST_WITH_ACTIVITYestablecido para ellos.

+0

http://stackoverflow.com/questions/35168769/start-in-foreground –

11

Como Dave already pointed out, podría ejecutar su Service con prioridad de primer plano. Pero esta práctica solo debe usarse cuando sea absolutamente necesario, es decir, cuando causaría una mala experiencia de usuario si el servicio fuera aniquilado por Android. Esto es lo que realmente significa el "primer plano": su aplicación está de alguna manera en primer plano y el usuario lo notaría inmediatamente si se mata (por ejemplo, porque reproducía una canción o un video).

¡En la mayoría de los casos, solicitar prioridad de primer plano para su Servicio es contraproducente!

¿Por qué es eso? Cuando Android decide matar un Service, lo hace porque le faltan recursos (generalmente RAM). En función de las diferentes clases de prioridad, Android decide qué procesos en ejecución, y esto incluye servicios, para finalizar con el fin de liberar recursos. Este es un proceso saludable que desea que suceda para que el usuario tenga una experiencia fluida. Si solicita prioridad en primer plano, sin una buena razón, solo para evitar que se mate su servicio, lo más probable es que cause una mala experiencia de usuario. ¿O puede garantizar que su servicio se mantenga dentro de un consumo mínimo de recursos y no tenga pérdidas de memoria?

Android proporciona sticky services para marcar servicios que deben reiniciarse después de un período de gracia si fue asesinado. Este reinicio generalmente ocurre dentro de unos segundos.

Imagen que desea escribir un cliente XMPP para Android. ¿Debería solicitar prioridad de primer plano para el Service que contiene su conexión XMPP? Definitivamente no, no hay absolutamente ninguna razón para hacerlo. Pero desea utilizar START_STICKY como indicador de devolución para el método onStartCommand de su servicio. De modo que su servicio se detiene cuando hay presión de recursos y se reinicia una vez que la situación vuelve a la normalidad.

: Estoy bastante seguro de que muchas aplicaciones de Android tienen pérdidas de memoria. Es algo que al programador casual (de escritorio) no le importa tanto.

+1

'START_STICKY' no es para ese uso, sino para garantizar que una tarea de tiempo limitado se concluye después de un proceso de matar. Si por alguna razón el servicio no se "pega" (por ejemplo, no se puede volver a conectar al servidor XMPP), el sistema puede decidir que intentó suficientes veces y simplemente dejar de reiniciar el servicio, sin mencionar que esto requeriría que el servicio siga funcionando en un bucle mientras la conexión está activa, lo que simplemente no se puede hacer. Dicho esto, no puedo encontrar una solución para mantener/reanudar la conexión entre las matanzas de procesos (aparte de programar intentos de reconexión periódicos a través de 'AlarmManager'). – Piovezan

+4

** 'START_STICKY' es exactamente lo que quiere usar aquí. ** *" ... intenté suficientes veces y simplemente dejé de reiniciar el servicio, ... "* No, el sistema Android no tiene conocimiento de la conexión XMPP (reintenta) una servicio pegajoso de Android realiza. Simplemente ve el servicio ejecutándose ** y lo mantiene funcionando **. Ese es el contrato que proporciona la API de Android si un servicio se inicia de manera permanente. * "... mencionar que esto requeriría que el servicio se ejecute en un bucle ..." * Sí, es exactamente por eso que (la mayoría) de los servicios de Android tienen un Looper (que generalmente se abstrae del usuario que usa un servicio de Android). – Flow

+0

Lo siento, lo confundí de [START_REDELIVER_INTENT] (http://stackoverflow.com/a/9441795/2241463). Aunque un servicio tiene ciertamente un Looper para manejar la cola de intentos que se le pasó, no se espera que lo mantenga funcionando de esa manera en el caso de una conexión persistente, sino que se transfiere un único intento y se mantiene un ciclo while dentro del 'Servicio. En su lugar, el método onStartCommand() 'o' IntentService.onHandleIntent() 'no es viable. – Piovezan

5

Tuve un problema similar. En algunos dispositivos después de un tiempo Android mata mi servicio e incluso startForeground() no ayuda. Y a mi cliente no le gusta este problema. Mi solución es usar la clase AlarmManager para asegurarme de que el servicio se esté ejecutando cuando sea necesario. Uso AlarmManager para crear un tipo de temporizador de vigilancia. Comprueba de vez en cuando si el servicio debería estar ejecutándose y lo reinicia. También uso SharedPreferences para mantener el indicador de si el servicio se debe ejecutar.

Creación/invocando mi temporizador de vigilancia:

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

recibir y procesar la intención del temporizador de vigilancia:

/** 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 
     } 
    } 
} 

De hecho yo uso WakefulBroadcastReceiver en lugar de BroadcastReceiver. Te di el código con BroadcastReceiver solo para simplificarlo.

1

Estoy trabajando en un problema de aplicación y cara de matar mi servicio al matar la aplicación. Investigué en Google y descubrí que tengo que ponerlo en primer plano. el siguiente es el código:

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

    } 
} 

lúpulos que puede ayudar !!!!

Cuestiones relacionadas