85 votes

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

Je lance un service à partir de mon activité Android principale 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 faisant disparaître 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 les services persistants avec les notifications à cause 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 de fonctionner lorsque l'application est fermée ?

48voto

3lomahmed Points 829

Je suis dans la même situation, jusqu'à présent j'ai appris que lorsque l'application est fermée, le service est également fermé parce qu'ils sont dans un seul thread, donc le service devrait être sur un autre thread pour qu'il ne soit pas fermé, examinez cela et cherchez à maintenir le service en vie avec le gestionnaire d'alarme, voici un exemple. http://www.vogella.com/articles/AndroidServices/article.html de cette façon, 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 le suivant startForeground() Le système est en effet conçu pour cela et il gère bien votre service.

13voto

alanban Points 131

Vous rendre service comme ceci 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() return START_STICKY

  2. onDestroy() -> startself

  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 y a un moyen de démarrerForeground sans Notification ,cherchez sur google

12voto

artex Points 435

Le présent peut vous aider. Je peux me tromper, mais il me semble que c'est lié au fait de renvoyer des documents. START_STICKY dans votre onStartCommand() méthode. Vous pouvez éviter que le service soit à nouveau appelé en renvoyant START_NOT_STICKY au lieu de cela.

11voto

mmmcho Points 149

Les services sont parfois très compliqués.

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

citant les notes du développeur

La plupart des confusions concernant la classe Service tournent en fait autour de ce qu'elle n'est pas :

Un service n'est pas un processus distinct. 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 non plus un moyen d'effectuer du travail en dehors du fil principal (pour éviter les erreurs "Application Not Responding").

Cela signifie que si l'utilisateur retire l'application des tâches récentes, votre processus sera supprimé (cela inclut toutes vos activités, etc.). Prenons maintenant trois scénarios.

Première où le service n'a pas une notification au premier plan.

Dans ce cas, votre processus est tué en même temps que votre service.

Deuxième où le service a une notification au premier plan

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

Troisièmement scénario Si le service n'a pas de notification au premier plan, il peut continuer à fonctionner si l'application est fermée. Nous pouvons le faire en exécutant le service dans un processus différent. (Cependant, j'ai entendu certaines personnes dire que cela pourrait ne pas fonctionner. Il ne tient qu'à vous d'en faire l'expérience )

vous pouvez créer un service dans un processus séparé en incluant l'attribut ci-dessous dans votre manifeste.

Android:process=":votreService"

o

Android:process="votreService" le nom du processus doit commencer par une minuscule.

citant les notes du développeur

Si le nom attribué à cet attribut commence par deux points (':'), un nouveau processus, privé pour l'application, est créé en cas de besoin et le service s'exécute dans ce processus. Si le nom du processus commence par un minuscules le service s'exécutera dans un processus global de ce nom, à condition qu'il en ait l'autorisation. 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, qu'il me corrige si je me trompe :)

6voto

Ajith K P Points 192

Le problème principal est l'impossibilité de démarrer le service lorsque l'application est fermée, Android OS( Dans certains systèmes d'exploitation Si vous n'êtes pas en mesure de redémarrer le service, appelez un responsable des alarmes pour qu'il démarre le récepteur comme ceci, voici le code complet, ce code maintiendra notre service en vie.

Le 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>

Dans l'activité principale, démarrez le gestionnaire d'alarme 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);

Ceci 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,

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X