web-dev-qa-db-fra.com

Android: maintenir un service d'arrière-plan en vie (prévenir la mort du processus)

J'ai un service qui se définit comme:

public class SleepAccelerometerService extends Service implements SensorEventListener

Essentiellement, je fais une application qui surveille l'activité de l'accéléromètre pour diverses raisons pendant que l'utilisateur dort avec son téléphone/appareil sur le lit. Il s'agit d'un service de longue durée qui NE DOIT PAS être tué pendant la nuit. Selon le nombre d'applications d'arrière-plan et de processus périodiques qui se produisent pendant la nuit, Android tue parfois mon processus, mettant ainsi fin à mon service. Exemple:

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}

Je ne veux pas forcer l'utilisateur à avoir "SleepActivity" ou une autre activité dans mon application comme premier plan. Je ne peux pas faire fonctionner mon service périodiquement, car il intercepte constamment onSensorChanged.

Des conseils? le code source est ici: http://code.google.com/p/electricsleep/

51
Jon Willis

Pour Android 2.0 ou version ultérieure, vous pouvez utiliser la méthode startForeground() pour démarrer votre service au premier plan.

Le la documentation dit ce qui suit :

Un service démarré peut utiliser l'API startForeground(int, Notification) pour mettre le service dans un état de premier plan, où le système le considère comme quelque chose que l'utilisateur est activement au courant et donc pas un candidat pour tuer lorsqu'il manque de mémoire. (Il est toujours théoriquement possible que le service soit tué sous une pression de mémoire extrême de l'application de premier plan actuelle, mais en pratique, cela ne devrait pas être un problème.)

Le est principalement destiné à lorsque le fait de tuer le service perturberait l'utilisateur, par ex. tuer un service de lecteur de musique arrêterait la lecture de la musique.

Vous devrez fournir un Notification à la méthode qui s'affiche dans la barre des notifications de la section En cours.

72
Dave Webb

Lorsque vous liez votre service à une activité avec BIND_AUTO_CREATE, votre service est tué juste après que votre activité a été détruite et non liée. Cela ne dépend pas de la façon dont vous avez implémenté votre méthode Services unBind, elle sera toujours supprimée.

L'autre façon consiste à démarrer votre service avec la méthode startService à partir de votre activité. De cette façon, même si votre activité est détruite, votre service ne sera pas détruit ni même interrompu, mais vous devrez le suspendre/le détruire vous-même avec stopSelf/stopService lorsque cela est approprié.

16
Witold Graca

Comme Dave l'a déjà souligné , vous pouvez exécuter votre Service avec la priorité au premier plan. Mais cette pratique ne doit être utilisée que lorsqu'elle est absolument nécessaire, c'est-à-dire lorsqu'elle entraînerait une mauvaise expérience utilisateur si le Service était tué par Android. Voici ce que signifie réellement le "premier plan": votre application est en quelque sorte au premier plan et l'utilisateur le remarquerait immédiatement s'il est tué (par exemple parce qu'il a joué une chanson ou une vidéo).

Dans la plupart des cas, demander la priorité de premier plan pour votre service est contre-productif!

Pourquoi donc? Lorsque Android décide de tuer un Service, il le fait parce qu'il manque de ressources (généralement de la RAM). En fonction des différentes classes de priorité, Android décide quels processus en cours d'exécution, y compris les services, doivent se terminer afin de libérer des ressources. Il s'agit d'un processus sain que vous souhaitez mettre en place afin que l'utilisateur ait une expérience fluide. Si vous demandez la priorité au premier plan, sans raison valable, juste pour éviter que votre service ne soit tué, cela entraînera très probablement une mauvaise expérience utilisateur. Ou pouvez-vous garantir que votre service reste dans une consommation de ressources minimale et n'a aucune fuite de mémoire?1

Android fournit services persistants pour marquer les services qui devraient être redémarrés après une période de grâce s'ils sont tués. Ce redémarrage se produit généralement en quelques secondes.

Image que vous souhaitez écrire un client XMPP pour Android. Devez-vous demander la priorité de premier plan pour le Service qui contient votre connexion XMPP? Certainement non, il n'y a absolument aucune raison de le faire. Mais vous souhaitez utiliser START_STICKY Comme indicateur de retour pour la méthode onStartCommand de votre service. Pour que votre service soit arrêté en cas de pression sur les ressources et redémarré une fois la situation revenue à la normale.

1: Je suis sûr que de nombreuses applications Android ont des fuites de mémoire. C'est quelque chose que le programmeur occasionnel (de bureau) ne se soucie pas beaucoup.

11
Flow

J'ai eu un problème similaire. Sur certains appareils après un certain temps Android tue mon service et même startForeground () n'aide pas. Et mon client n'aime pas ce problème. Ma solution est d'utiliser - AlarmManager classe pour s'assurer que le service fonctionne quand il est nécessaire. J'utilise AlarmManager pour créer une sorte de temporisateur de surveillance. Il vérifie de temps en temps si le service doit être exécuté et le redémarrer. J'utilise aussi SharedPreferences pour garder le drapeau indiquant si le service doit être en cours d'exécution.

Création/fermeture de ma minuterie de surveillance:

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

Réception et traitement de l'intention du temporisateur de surveillance:

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

En effet j'utilise WakefulBroadcastReceiver au lieu de BroadcastReceiver . Je vous ai donné le code avec BroadcastReceiver juste pour le simplifier.

5
ivan

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

public static final int BIND_ABOVE_CLIENT - Ajouté dans API niveau 14

Indicateur pour bindService(Intent, ServiceConnection, int): indique que l'application cliente liant à ce service considère que le service est plus important que l'application elle-même. Une fois définie, la plate-forme essaiera de tuer le tueur en mémoire de l'application avant de tuer le service auquel il est lié, bien que cela ne soit pas garanti.

Les autres drapeaux du même groupe sont: BIND_ADJUST_WITH_ACTIVITY, BIND_AUTO_CREATE, BIND_IMPORTANT, BIND_NOT_FOREGROUND, BIND_WAIVE_PRIORITY.

Notez que la signification de BIND_AUTO_CREATE a changé dans ICS, et anciennes applications qui ne spécifient pasBIND_AUTO_CREATE aura automatiquement les drapeauxBIND_WAIVE_PRIORITY etBIND_ADJUST_WITH_ACTIVITY défini pour eux.

4

Je travaille sur une application et je suis confronté au problème de la suppression de mon service par la suppression de l'application. J'ai fait des recherches sur Google et j'ai découvert que je devais le mettre au premier plan. voici le code:

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

    }
}

Houblon que cela peut aider !!!!

2
Irfan Ul Haq

Gardez votre empreinte de service petite, cela réduit la probabilité de Android fermer votre application. Vous ne pouvez pas l'empêcher d'être tué car si vous le pouviez, les gens pourraient facilement créer des logiciels espions persistants

2
BeRecursive