web-dev-qa-db-fra.com

Le processus du service est arrêté après le retrait de l'application du volet Applications.

Je démarre un service (ou redémarre le service en cours d'exécution) lorsqu'une activité est lancée, en utilisant:

Intent intent = new Intent(this, MyService.class); startService(intent); 

Ensuite, en fonction de certaines actions, la même activité est liée au service à l’aide de

bindService(new Intent(this, MyService.class), mConnection, Context.BIND_AUTO_CREATE);

Et quand l'activité est détruite, j'appelle 

unbindService(mConnection);

Auparavant, le service redémarrait lorsque j'avais tué la même activité/application dans la barre des tâches et affiché le message "Processus 1 du service 1 en cours d'exécution" dans les applications en cours d'exécution. 

Désormais, le service ne redémarre pas lorsque vous supprimez la même activité/application.

Et je reçois le message "0 processus 1 service en cours d'exécution" , ce qui signifie que le service n'est pas en cours d'exécution.

Le service ne redémarre pas à la fermeture de l'application. Mon application consiste en une activité. De plus, le service est démarré avec succès lorsqu'il est lancé après un démarrage du système.

Pourquoi le processus du service est-il tué quand je le lance en utilisant startService () ??

modifier

Le service avait l'habitude de redémarrer plus tôt après la fermeture de l'application à partir du volet Applications. Mais maintenant, avec le code SAME, ce n’est pas le cas. Cela arrive aussi avec d'autres applications quand je les ferme. par exemple. 

enter image description here

28
geekoraul

Voici une solution de contournement que j'ai découverte et qui fonctionne bien pour relancer un service si son processus est tué à la fermeture de l'application. Dans votre service, ajoutez le code suivant.

Je suis tombé sur cette solution de contournement dans this thread. 

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

Semble être un bogue que le processus de l'application est tué. Il est inutile qu'un service s'exécute si son processus est tué.

50
geekoraul

S'il vous plaît être conscient de cela: onDestroy n'est pas toujours appelé. Vous ne devriez pas mettre le code de cette façon.
Lorsque l'activité est forcée fermée ou fermée de manière anormale par le système, onDestroy n'est pas appelé.

6
Nick Jian

Malheureusement, il s’agit d’un problème compliqué en raison du fonctionnement d’Android. Il existe un certain nombre de stratégies qui traitent chacune différentes parties du problème. Pour de meilleurs résultats, combinez plusieurs stratégies.

Notez que certaines de ces stratégies peuvent ne plus être nécessaires dans les versions plus récentes d'Android.

1. Commencer une activité

Que faire

Déconnecté de Service de premier plan tué lors de la réception d'une émission après qu'une activité a été balayée dans la liste des tâches :

Au premier plan du service:

  @Override
    public void onTaskRemoved( Intent rootIntent ) {
       Intent intent = new Intent( this, DummyActivity.class );
       intent.addFlags( Intent.FLAG_ACTIVITY_NEW_TASK );
       startActivity( intent );
    }

Dans le manifeste:

  <activity
    Android:name=".DummyActivity"
    Android:theme="@Android:style/Theme.NoDisplay"
    Android:enabled="true"
    Android:allowTaskReparenting="true"
    Android:noHistory="true"
    Android:excludeFromRecents="true"
    Android:alwaysRetainTaskState="false"
    Android:stateNotNeeded="true"
    Android:clearTaskOnLaunch="true"
    Android:finishOnTaskLaunch="true"
    /> 

(Si votre service est dans un processus différent, définissez le processus de cette activité sur le même processus.)

Dans DummyActivity.Java:

  public class DummyActivity extends Activity {
        @Override
        public void onCreate( Bundle icicle ) {
            super.onCreate( icicle );
            finish();
        }
    }

Effets secondaires

Provoque la fermeture de l'activité récente. Normalement, balayer une application ne ferme pas l'activité récente.

Désavantages

Cela ne prend effet que lorsque l'activité fictive démarre , ce qui peut prendre une demi-seconde ou plus, de sorte que le service risque toujours d'être tué un instant.

Explication

Lorsque vous supprimez/balayez votre application, un indicateur appelé waitingToKill est set . Lorsque cet indicateur est défini, Android peut interrompre le processus à tout moment dans le futur , tel que lorsque vous recevez une émission . Commencer une activité efface ce drapeau.

2. Spam a BroadcastReceiver with retransmissions au premier plan

Que faire

Fusionner ceci dans votre code de service:

if (Build.VERSION.SDK_INT >= 16) {
    Intent intent = new Intent(this, DummyReceiver.class);
    intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);

    //This seems to be timing-related; the more times we do this,
    //the less likely the process gets killed
    for (int i = 0; i < 50; ++i)
        sendBroadcast(intent);
}

Créez un récepteur de diffusion factice:

public class DummyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {}
}

Ajoutez le destinataire à votre manifeste:

<receiver Android:name=".DummyReceiver" />

Effets secondaires

Peut provoquer un léger retard (~ 250 ms)/blocage lorsque la tâche est supprimée de l'écran Récents.

Désavantages

Cela ne fait que maintenir le processus en cours pendant la réception des émissions. the waitingToKill flag est toujours défini sur, de sorte que le processus peut toujours être supprimé par la suite, par exemple lors de la réception d'une émission.

Explication

Si votre processus ne fonctionne pas en priorité au premier plan, Android essaiera de le tuer immédiatement . La réception d’émissions de premier plan l’empêche temporairement, ce qui entraîne la définition de l’indicateur waitingToKill .

3. Ne pas lier aux services

La liaison à un service semble augmenter la probabilité que le processus du service soit tué immédiatement lorsqu'une tâche est supprimée.

3
Sam

Je sais que cette question est ancienne, mais j'ai récemment rencontré ce problème et, tout à coup, mon service s'est arrêté lors de la fermeture de l'application. Auparavant, cela fonctionnait bien. Ce problème m'a fait perdre beaucoup de temps. Si vous rencontrez des problèmes similaires, assurez-vous que VOTRE RESTRICTION DE DONNÉES DE FOND IS est désactivé . C’est le problème que j’ai eu et cela a du sens car lorsque le traitement des données en arrière-plan est restreint, le processus en arrière-plan restreint ne sera pas exécuté.

1
kapil kumar

onDestroy n'est pas toujours appelé. Le principal problème dans votre cas est votre impossibilité de démarrer le service à la fermeture de l'application. Android OS ( Dans Certains OS ) tuera le service. Si vous ne parvenez pas à redémarrer le service, appelez une alarme. crèche pour démarrer le reciver comme ça,

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");
    }
}
1
Ajith K P