2011-07-08 10 views
7

He comenzado un servicio en mi nueva aplicación. El servicio está en primer plano, con una Notificación. Cuando esto se ejecuta en el nivel 7 de la API AVD 2.1, todo funciona bien. Pero cuando se ejecuta en una Samsung Galaxy Tab que ejecuta Gingerbread, el servicio se iniciará (el icono y el nombre de la aplicación aparecerán en la parte superior del área de notificación), pero luego de unos segundos, el servicio desaparecerá. La última entrada en el registro que puedo ver está asociada a mi aplicación, es el resultado de mi Log.d ("Taglines", "Returning with" + START_STICKY), que precede inmediatamente a "return START_STICKY". en mi anulación onStartCommand del servicio, de la siguiente manera:START_STICKY, el servicio de primer plano de Android se va sin previo aviso

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

    int rc ; 
    Log.d("Taglines","onStartCommand()"); 
    Toast.makeText(this, "Starting service TagsManager", Toast.LENGTH_SHORT).show(); 
    Log.d("Taglines","Calling super.onStartCommand()"); 
    rc = super.onStartCommand(intent,flags,startId); 
    Log.d("Taglines","super.onStartCommand return code was " + rc); 
    createNotification(INITIAL_NOTIFICATION_TEXT); 
    Log.d("Taglines","Returning with " + START_STICKY); 
    return START_STICKY ; 
} 

La notificación se establece así:

Este es el resultado de "Logcat adb" cuando se inicia el servicio:

D/Taglines(21863): Starting service 
D/Taglines(21863): TagsManager(nullary) completed 
D/Taglines(21863): onStartCommand() 
D/Taglines(21863): Calling super.onStartCommand() 
D/Taglines(21863): super.onStartCommand eturn code was 2 
D/Taglines(21863): createNotification called 
D/Taglines(21863): Obtained reference to Notification Manager 
D/Taglines(21863): createNotificacion() .. getApplicationContext 
D/Taglines(21863): createNotificacion() ... passing notification 
D/Taglines(21863): Starting foreground 
D/Taglines(21863): Started 
D/Taglines(21863): Returning with 1 

Después de eso, nada especial (nada en absoluto de PID 21863). Sólo un montón de:

D/KeyguardViewMediator( 302): setHidden false 
D/KeyguardViewMediator( 302): setHidden false 
D/KeyguardViewMediator( 302): setHidden false 
D/KeyguardViewMediator( 302): setHidden false 
D/KeyguardViewMediator( 302): setHidden false 
W/InputManagerService( 302): Window already focused, ignoring focus gain of:   [email protected] 
D/KeyguardViewMediator( 302): setHidden false 
D/KeyguardViewMediator( 302): setHidden false 
D/KeyguardViewMediator( 302): setHidden false 
D/KeyguardViewMediator( 302): setHidden false 
D/KeyguardViewMediator( 302): setHidden false 
D/KeyguardViewMediator( 302): setHidden false 
D/KeyguardViewMediator( 302): setHidden false 
D/KeyguardViewMediator( 302): setHidden false 
D/KeyguardViewMediator( 302): setHidden false 

No creo que se necesita en este caso, pero aquí está la parte correspondiente de la AndroidManifest.xml:

<service android:name=".TagsManager" 
      android:exported="false"> 
    </service> 

¿Dónde podría haber ido mal? ¿Qué otra información puedo proporcionar?

+0

Hmmm ... He leído más sobre startForeground, y parece que esto solo establece un indicador en un objeto de notificación, en lugar de tomar alguna medida. Así que por capricho, invertí la secuencia de modo que ahora startForeground preceda a NotificationManager.notify. Hasta el momento, se ve bastante bien. Así que ahora estoy buscando ese ejemplo que me llevó a hacerlo de otra manera ... – Dennis

+0

Lamentablemente, el éxito de revertir esa secuencia fue de corta duración. Parece ser un poco arriesgado si el adhesivo se "pegará". Con _muchas_ docenas de intentos para comenzar este servicio, he tenido que continuar tres veces hasta ahora. :( – Dennis

+0

Bueno, ¿su Galaxy Tab experimentaba condiciones de poca memoria, o tal vez su Servicio estaba haciendo algo de memoria intensiva en el hilo principal? –

Respuesta

10

algunas cosas:

  1. deshacerse del mNotificationManager.notify(NOTIFICATION_ID, notification);. startForeground() muestra el icono de notificación para usted.

  2. Foreground Service s todavía se pueden matar, es menos probable que lo sean.

  3. Hay un error en 2.3 (no estoy seguro si aún estaba fija), donde cuando un Service se mata, se arrancará de su onStartCommand() no serán llamados de nuevo. En su lugar, tendrá que realizar cualquier configuración en onCreate().

+0

Muchas gracias, todo esto tiene sentido. He intentado lo que dijo, y así ahora se ve positivo. – Dennis

+0

+1 muchas gracias. Insecto aquí en 2.3, error en iOS ... Cómo escribir un software para mi cliente si el sistema operativo tiene errores en todas partes :) - ¡yah, con marcos independientes de la plataforma! :) He utilizado START_STICKY y onDestroy() volverá a crear a veces ... –

1

Ambos códigos sólo son relevantes cuando el teléfono se queda sin memoria y mata al Service antes de que termine la ejecución. START_STICKY le dice al sistema operativo que vuelva a crear el servicio después de que tenga suficiente memoria y llame de nuevo al onStartCommand() con un intento nulo. START_NOT_STICKY le dice al sistema operativo que no se moleste en volver a crear el servicio. También hay un tercer código START_REDELIVER_INTENT que le dice al sistema operativo que vuelva a crear el Service Y vuelva a enviar el mismo intento a onStartCommand().

This article por Dianne Hackborn explicaron los antecedentes de esto mucho mejor que la documentación oficial.

La parte clave aquí es un nuevo código de resultado devuelto por la función, contando el sistema lo que debe hacer con el servicio si su proceso es asesinada mientras se está ejecutando:

START_STICKY es básicamente el mismo que el comportamiento anterior, donde el servicio se deja "iniciado" y luego será reiniciado por el sistema. La única diferencia con las versiones anteriores de la plataforma es que si se reinicia porque su proceso se cancela, se llamará a onStartCommand() en la siguiente instancia del servicio con un Intento nulo en lugar de no llamarse en absoluto . Los servicios que usan este modo deben llamar al para verificar siempre este caso y tratarlo adecuadamente.

START_NOT_STICKY dice que, después de regresar de onStartCreated(), si se elimina el proceso sin comienzo restante manda a entregar, entonces el servicio se detendrá en lugar de reiniciarse. Esto hace que un tenga mucho más sentido para los servicios que solo se ejecutan mientras se ejecutan los comandos . Por ejemplo, se puede iniciar un servicio cada 15 minutos desde una alarma para sondear algún estado de la red. Si se hace muerto mientras se hace ese trabajo, lo mejor sería dejar que sea detenido y comenzar la próxima vez que se active la alarma.

START_REDELIVER_INTENT es como START_NOT_STICKY, excepto si el proceso del servicio se mató antes de que llama stopSelf() para un determinado intención, que la intención será re-entregado a ella hasta que se complete (a menos que después de una cierta cantidad de más tries aún no puede completarse, en punto que el sistema abandona). Esto es útil para los servicios que son recibiendo comandos de trabajo que hacer, y quiere asegurarse de que lo hagan , eventualmente completar el trabajo para cada comando enviado.

Cuestiones relacionadas