web-dev-qa-db-fra.com

Continuer le service même si l'application est supprimée de l'application récente

J'ai un petit problème.

Dans mon application, un service est démarré après que l'utilisateur est connecté avec succès. Auparavant, le service devait s’arrêter si l’application était supprimée. (Disons, supprimez de la liste des applications récentes en balayant.) Nous avions donc utilisé Android:stopWithTask="true". Nous avons maintenant besoin que le service fonctionne tel quel, même si la tâche qui l'a démarré est supprimée de la liste des applications récentes. J'ai donc changé le service pour inclure Android:stopWithTask="false". Mais cela ne semble pas fonctionner.

Code associé:

Voici la partie manifeste liée au service:

<service
    Android:enabled="true"
    Android:name=".MyService"
    Android:exported="false"
    Android:stopWithTask="false" />

Dans MyService.Java:

public class MyService extends AbstractService {

    @Override
    public void onStartService() {
        Intent intent = new Intent(this, MyActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
        Notification notification = new Notification(R.drawable.ic_launcher, "My network services", System.currentTimeMillis());
        notification.setLatestEventInfo(this, "AppName", "Message", pendingIntent);
        startForeground(MY_NOTIFICATION_ID, notification);  
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        Toast.makeText(getApplicationContext(), "onTaskRemoved called", Toast.LENGTH_LONG).show();
        System.out.println("onTaskRemoved called");
        super.onTaskRemoved(rootIntent);
    }
}

AbstractService.Java est une classe personnalisée qui étend Sevrice:

public abstract class AbstractService extends Service {

    protected final String TAG = this.getClass().getName();

    @Override
    public void onCreate() {
        super.onCreate();
        onStartService();
        Log.i(TAG, "onCreate(): Service Started.");
    }

    @Override
    public final int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStarCommand(): Received id " + startId + ": " + intent);
        return START_STICKY; // run until explicitly stopped.
    }

    @Override
    public final IBinder onBind(Intent intent) {
        return m_messenger.getBinder();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        onStopService();
        Log.i(TAG, "Service Stopped.");
    }    

    public abstract void onStartService();
    public abstract void onStopService();
    public abstract void onReceiveMessage(Message msg);

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        Toast.makeText(getApplicationContext(), "AS onTaskRemoved called", Toast.LENGTH_LONG).show();
        super.onTaskRemoved(rootIntent);
    }
}

Maintenant, si je me connecte à l'application, MyService est démarré. Après cela, j'appuie sur le bouton Home, l'application est donc déplacée en arrière-plan. Maintenant, je retire l'application de la liste des applications récentes. À ce moment-là, je devrais voir le message de Toast et de la console, conformément à la description de cette méthode:

public void onTaskRemoved (Intention rootIntent)

Ajouté dans l'API niveau 14

Ceci est appelé si le service est en cours d'exécution et que l'utilisateur a supprimé une tâche provenant de l'application du service. Si vous avez défini ServiceInfo.FLAG_STOP_WITH_TASK, vous ne recevrez pas ce rappel. au lieu de cela, le service sera simplement arrêté.

Paramètres rootIntent Intention racine d'origine utilisée pour lancer la tâche en cours de suppression.

Mais je ne vois rien de cela. Le service renvoie START_STICKY dans onStartCommand, je pense donc que onTaskRemoved devrait être déclenché avec l'indicateur Android:stopWithTask="false".

Est-ce que je manque quelque chose?

Faites-moi savoir au cas où je devrais ajouter un code qui pourrait être important pour comprendre ce qui ne va pas.

P.S.: J'ai testé cela sur 4.2.2 jusqu'à maintenant.

P.S.: Je viens de tester le même code dans la version 4.1.2, sur laquelle le service continue de tourner, et je reçois également le message "onTaskRemoved appelé" dans le journal.

Que dois-je faire pour que cela fonctionne dans toutes les versions?

52
MysticMagicϡ

Suivez simplement ces scénarios, votre service et vos processus (les threads s'exécutant dans votre service) resteront continus.

  1. Créez un service et utilisez START_STICKY comme valeur de retour dans la méthode onStartCommand comme ci-dessous:

    @Override
    public int onStartCommand(final Intent intent, 
                              final int flags,
                              final int startId) {
    
        //your code
        return START_STICKY;
    }  
    
  2. Le code ci-dessus redémarre le service s'il est détruit et reste toujours actif, mais le processus (threads) exécuté à partir du service cesse de fonctionner si votre application est supprimée des applications récentes. Pour vous assurer que vos processus (Threads) restent toujours en état d'exécution, vous devez remplacer la méthode onTaskRemoved () et ajouter du code pour redémarrer les tâches comme ci-dessous.

    @Override
    public void onTaskRemoved(Intent rootIntent){
        Intent restartServiceTask = new Intent(getApplicationContext(),this.getClass());
        restartServiceTask.setPackage(getPackageName());    
        PendingIntent restartPendingIntent =PendingIntent.getService(getApplicationContext(), 1,restartServiceTask, PendingIntent.FLAG_ONE_SHOT);
        AlarmManager myAlarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
        myAlarmService.set(
                AlarmManager.ELAPSED_REALTIME,
                SystemClock.elapsedRealtime() + 1000,
                restartPendingIntent);
    
        super.onTaskRemoved(rootIntent);
    }
    
  3. Démarrer le service comme ci-dessous

startService (nouvelle intention (this, YourService.class));

31
Avnish Choudhary

Dans votre service, ajoutez le code suivant. Cela me convient dans 4.4.2

Voici une solution de contournement que j'ai rencontrée et qui fonctionne bien pour relancer un service si son processus est tué à la fermeture de l'application.

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

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

     super.onTaskRemoved(rootIntent); 
}
8
Selim Raza

Si vous vous liez à votre service à partir d'une sous-classe de la classe Application et que vous conservez votre connexion IBinder, le service restera actif même après la suppression de l'application des applications récentes.

1
Nima G