web-dev-qa-db-fra.com

Le service Android s'arrête lorsque l'application est fermée

Je démarre un service à partir de mon activité principale sur Android comme suit:

final Context context = base.getApplicationContext();
final Intent intent = new Intent(context, MyService.class);
startService(intent);

Lorsque je ferme la page d'activité en la glissant de la liste des applications récentes, le service s'arrête et redémarre au bout d'un certain temps. Je ne peux pas utiliser de services persistants avec des notifications en raison des exigences de mon application. Comment puis-je faire en sorte que le service ne redémarre pas ou ne s'arrête pas et continue à fonctionner à la sortie de l'application?

66
Bam

Je suis dans la même situation. Jusqu'à présent, j'ai appris que, lorsque l'application est fermée, le service est fermé également parce qu'ils sont dans un seul thread. Le service doit donc être sur un autre thread afin de ne pas le fermer. et cherchez à maintenir le service actif avec le gestionnaire d’alarmes ici un exemple http://www.vogella.com/articles/AndroidServices/article.html ainsi, votre service ne sera pas affiché dans la notification.

enfin, après toutes les recherches que j'ai effectuées, je me rends compte que le meilleur choix pour un service de longue durée est startForeground() , car il est conçu pour cela et le système gère bien votre service.

38
aljuaid86

Ceci peut vous aider. Je peux me tromper, mais il me semble que cela est lié au renvoi de START_STICKY dans votre méthode onStartCommand(). Vous pouvez éviter que le service ne soit appelé à nouveau en renvoyant START_NOT_STICKY à la place.

12
artex

vous rendre service comme ça dans votre Mainifest 

 <service
            Android:name=".sys.service.youservice"
            Android:exported="true"
        Android:process=":ServiceProcess" />

alors votre service s'exécutera sur un autre processus nommé ServiceProcess


si vous voulez que votre service ne meure jamais:

  1. onStartCommand () renvoie START_STICKY

  2. onDestroy () -> startelf

  3. créer un service Deamon 

  4. jin -> créer un processus Native Deamon, vous pouvez trouver des projets open-source sur github

  5. startForeground (), il existe un moyen de démarrer en arrière-plan sans notification, google it

12
alanban

Les services sont parfois assez compliqués.

Lorsque vous démarrez un service à partir d'une activité (ou de votre processus), le service est essentiellement sur le même processus.

citant les notes du développeur

La plus grande confusion à propos de la classe de service tourne autour de ce qu'elle n'est pas:

Un service n'est pas un processus séparé. L'objet Service lui-même n'implique pas qu'il s'exécute dans son propre processus; sauf indication contraire, il s'exécute dans le même processus que l'application dont il fait partie.

Un service n'est pas un fil. Ce n'est pas un moyen en soi de travailler en dehors du thread principal (pour éviter les erreurs Application Not Responding).

Cela signifie donc que si l'utilisateur balaie l'application loin des tâches récentes, il supprimera votre processus (cela inclut toutes vos activités, etc.). Maintenant, prenons trois scénarios. 

Premieroù le service n'a pas une notification de premier plan.

Dans ce cas, votre processus est tué avec votre service.

Secondoù le service a une notification de premier plan

Dans ce cas, le service n'est pas tué et le processus non plus.

Troisièmescénario Si le service n'a pas de notification de premier plan, il peut toujours continuer à fonctionner si l'application est fermée. Nous pouvons le faire en faisant fonctionner le service dans un processus différent. (Cependant, j'ai entendu certaines personnes dire que cela pourrait ne pas fonctionner. À vous de l'essayer vous-même)

vous pouvez créer un service dans un processus distinct en incluant l'attribut ci-dessousdans votre manifeste.

Android: process = ": yourService"

ou

Android: process = "yourService" nom du processus doit commencer par minuscule.

citant des notes de développeur

Si le nom attribué à cet attribut commence par un signe deux-points (':'), un nouveau processus, privé pour l'application, est créé lorsqu'il est nécessaire et le service s'exécute dans ce processus. Si le nom du processus commence par un caractère minuscule , le service s'exécutera dans un processus global portant ce nom, à condition qu'il y soit autorisé. Cela permet aux composants de différentes applications de partager un processus, réduisant ainsi l'utilisation des ressources.

c'est ce que j'ai compris, si quelqu'un est un expert, corrigez-moi si je me trompe :)

3
mmmcho

Problème principal lorsqu’il est impossible de démarrer le service à la fermeture de l’application, Android OS ( Dans Certains OS ) tuera le service pour l’optimisation des ressources. Si vous ne parvenez pas à redémarrer le service, appelez un gestionnaire d’alarmes pour démarrer le récepteur. comme ceci, Voici le code complet, Ce code gardera en vie votre service.

Manifeste est,

         <service
            Android:name=".BackgroundService"
            Android:description="@string/app_name"
            Android:enabled="true"
            Android:label="Notification" />
        <receiver Android:name="AlarmReceiver">
            <intent-filter>
                <action Android:name="REFRESH_THIS" />
            </intent-filter>
        </receiver>

IN Main Activty lance le gestionnaire d’alarmes de cette manière,

String alarm = Context.ALARM_SERVICE;
        AlarmManager am = (AlarmManager) getSystemService(alarm);

        Intent intent = new Intent("REFRESH_THIS");
        PendingIntent pi = PendingIntent.getBroadcast(this, 123456789, intent, 0);

        int type = AlarmManager.RTC_WAKEUP;
        long interval = 1000 * 50;

        am.setInexactRepeating(type, System.currentTimeMillis(), interval, pi);

cela appellera reciver et reciver est,

public class AlarmReceiver extends BroadcastReceiver {
    Context context;

    @Override
    public void onReceive(Context context, Intent intent) {
        this.context = context;

        System.out.println("Alarma Reciver Called");

        if (isMyServiceRunning(this.context, BackgroundService.class)) {
            System.out.println("alredy running no need to start again");
        } else {
            Intent background = new Intent(context, BackgroundService.class);
            context.startService(background);
        }
    }

    public static boolean isMyServiceRunning(Context context, Class<?> serviceClass) {
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);

        if (services != null) {
            for (int i = 0; i < services.size(); i++) {
                if ((serviceClass.getName()).equals(services.get(i).service.getClassName()) && services.get(i).pid != 0) {
                    return true;
                }
            }
        }
        return false;
    }
}

Et ce récepteur Alaram appelle une fois lorsque l'application Android est ouverte et lorsque l'application est fermée. Le service est ainsi,

public class BackgroundService extends Service {
    private String LOG_TAG = null;

    @Override
    public void onCreate() {
        super.onCreate();
        LOG_TAG = "app_name";
        Log.i(LOG_TAG, "service created");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(LOG_TAG, "In onStartCommand");
        //ur actual code
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        // Wont be called as service is not bound
        Log.i(LOG_TAG, "In onBind");
        return null;
    }

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    @Override
    public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent);
        Log.i(LOG_TAG, "In onTaskRemoved");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(LOG_TAG, "In onDestroyed");
    }
}
2
Ajith K P

essayez ceci, le service restera actif en arrière-plan.

BackServices.class

public class BackServices extends Service{

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
   public int onStartCommand(Intent intent, int flags, int startId) {
      // Let it continue running until it is stopped.
      Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
      return START_STICKY;
   }
   @Override
   public void onDestroy() {
      super.onDestroy();
      Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
   }
}

dans votre MainActivity onCreate, supprimez cette ligne de code 

startService(new Intent(getBaseContext(), BackServices.class));

Maintenant, le service continuera à fonctionner en arrière-plan.

2
Youssef Al Subaihi

Depuis Android O, vous ne pouvez pas utiliser les services pour les opérations en arrière-plan longues, pour cette raison, https://developer.Android.com/about/versions/oreo/background . Jobservice sera la meilleure option avec l'implémentation de Jobscheduler.

1
abhi.nalwade

Utiliser le même processus pour le service et l'activité et START_STICKY ou START_REDELIVER_INTENT dans le service est le seul moyen de pouvoir redémarrer le service lorsque l'application redémarre, ce qui se produit lorsque l'utilisateur ferme l'application par exemple, mais également lorsque le système le décide. de le fermer pour des raisons d'optimisation. Vous NE POUVEZ PAS avoir un service qui fonctionnera de manière permanente sans aucune interruption. En raison de leur conception, les smartphones ne sont pas conçus pour exécuter des processus continus pendant une longue période. Cela est dû au fait que la vie de la batterie est la plus haute priorité. Vous devez concevoir votre service pour qu'il soit arrêté à tout moment.

1
stef

La meilleure solution consiste à utiliser l'adaptateur de synchronisation sous Android pour démarrer le service. Créez un adaptateur de synchronisation et appelez le service de démarrage leur méthode .. à l'intérieur de la méthode onPerformSync. Pour créer un compte de synchronisation, veuillez vous référer à ce lien https://developer.Android.com/training/sync-adapters/index.html

Pourquoi SyncAdapter? Réponse: Parce que vous utilisiez auparavant le service en utilisant le contexte de votre application. Ainsi, chaque fois que le processus de votre application est tué (lorsque vous le supprimez du gestionnaire de tâches ou du système d'exploitation, supprimez-le en raison d'un manque de ressources), votre service sera également supprimé. SyncAdapter ne fonctionnera pas dans le thread de l'application .. donc si vous appelez à l'intérieur .. le service ne sera plus supprimé .. sauf si vous écrivez du code pour le supprimer. 

1
Nishanth S Babu

Vous devez ajouter ce code dans votre classe de service pour que celle-ci gère le cas lorsque votre processus est arrêté 

 @Override
    public void onTaskRemoved(Intent rootIntent) {
        Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
        restartServiceIntent.setPackage(getPackageName());

        PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
        AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
        alarmService.set(
                AlarmManager.ELAPSED_REALTIME,
                SystemClock.elapsedRealtime() + 1000,
                restartServicePendingIntent);

        super.onTaskRemoved(rootIntent);
    }
0
Kaustubh Bhagwat

L'exécution d'un service d'intention sera plus facile. Service en créant un thread dans l'application mais il est toujours dans l'application. 

0
Seb
<service Android:name=".Service2"
            Android:process="@string/app_name"
            Android:exported="true"
            Android:isolatedProcess="true"
            />

Déclarez ceci dans votre manifeste. Attribuez un nom personnalisé à votre processus, puis isolez-le et exportez-le. 

0
Nishanth S Babu