web-dev-qa-db-fra.com

Impossible de garder le service Android en vie après la fermeture de l'application

J'essaie de créer un service qui reste actif tout le temps, même si l'utilisateur ferme l'application. Selon ces fils

Maintenir le service de localisation actif lors de la fermeture de l'application

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

Android: garder le service en marche quand l'application est tuée

cela peut être accompli avec IntentServices ou Service.START_STICKY

Pourtant, j'ai essayé les deux types de services sans succès. En d'autres termes, mes services sont supprimés lorsque l'application est fermée par l'utilisateur. Quelqu'un peut-il indiquer si cela peut être fait et comment? Voici ce que j'ai essayé sans succès:

Avec IntentService:

public class MyIntentService extends IntentService {
    private final int mPollingTimeMS = 500;
    private int mInitializationPollingCount = 0;
    private Thread mPollThread;
    public MyIntentService() {
        super("MyIntentService");
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        mPollThread = new Thread() {
            public void run() {
                while (true) {
                    try {
                        Log.e(Constants.Engine.LOGGER_TAG_DEV,
                                "SDK Service Running: " +
                                        mInitializationPollingCount * mPollingTimeMS +
                                        "ms have elapsed");
                        mInitializationPollingCount++;
                        sleep(mPollingTimeMS);

                    } catch (Exception e) {
                        StackTraceElement trace = new Exception().getStackTrace()[0];
                        Logger.e(Constants.Engine.LOGGER_TAG_APP, "[Exception:" + e.toString() + "]" +
                                trace.getClassName() + "->" + trace.getMethodName() + ":" + trace.getLineNumber());
                    }
                }
            }
        };
        mPollThread.start();
    }
}

et avec les services:

public class MyService extends Service {
    public MyService() {
    }
    private final int mPollingTimeMS = 500;
    private int mInitializationPollingCount = 0;
    private Thread mPollThread;
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        mPollThread = new Thread() {
            public void run() {
                while (true) {
                    try {
                        Log.e(Constants.Engine.LOGGER_TAG_DEV,
                                "SDK Service Running: " +
                                        mInitializationPollingCount * mPollingTimeMS +
                                        "ms have elapsed");
                        mInitializationPollingCount++;
                        sleep(mPollingTimeMS);

                    } catch (Exception e) {
                        StackTraceElement trace = new Exception().getStackTrace()[0];
                        Logger.e(Constants.Engine.LOGGER_TAG_APP, "[Exception:" + e.toString() + "]" +
                                trace.getClassName() + "->" + trace.getMethodName() + ":" + trace.getLineNumber());
                    }
                }
            }
        };
        mPollThread.start();
        return Service.START_STICKY;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // I tried to return null here, but this
        // service gets killed no matter what.
        return null;
    }
}

et voici le manifeste:

    <service
        Android:name=".mycompany.MyService"
        Android:enabled="true"
        Android:exported="true"
        Android:process=":process1">
    </service>
    <service
        Android:name=".mycompany.MyIntentService"
        Android:process=":process2"
        Android:exported="false">
    </service>

J'ajouterai que je ferme l'application de test non pas avec un bouton de fermeture, mais en utilisant le gestionnaire d'applications Android OS. Voir l'image ci-dessous

 enter image description here

Enfin, l'activité du conducteur (pas grand chose là-bas)

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent1 = new Intent(getBaseContext(), MyService.class);
        startService(intent1);
        Intent intent2 = new Intent(getBaseContext(), MyIntentService.class);
        startService(intent2);

    }
}

J'essaie également d'ajouter une notification et d'en faire un service de premier plan, mais toujours la même chose. Au moment où je ferme l'application, tout est tué. C'est ce que j'ai ajouté:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    showNotification();
...etc..

private void showNotification() {
    Intent notificationIntent = new Intent(this, MainActivity.class);
    notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
            notificationIntent, 0);
    int iconId = R.mipmap.ic_launcher;
    int uniqueCode = new Random().nextInt(Integer.MAX_VALUE);
    Notification notification = new NotificationCompat.Builder(this)
            .setSmallIcon(iconId)
            .setContentText("Context Text")
            .setContentIntent(pendingIntent).build();
    startForeground(uniqueCode, notification);
}
9
gmmo

Voici un exemple de service de premier plan que j'utilise et qui fonctionne, il reste actif lorsque l'application est fermée. Bien sûr, il doit également être démarré. Pour cette tâche, l'application doit être exécutée à première vue ou le destinataire d'un événement de démarrage doit être défini, mais il s'agit d'une autre histoire.

public class MyService extends Service {
static final int NOTIFICATION_ID = 543;

public static boolean isServiceRunning = false;

@Override
public void onCreate() {
    super.onCreate();
    startServiceWithNotification();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (intent != null && intent.getAction().equals(C.ACTION_START_SERVICE)) {
        startServiceWithNotification();
    }
    else stopMyService();
    return START_STICKY;
}

// In case the service is deleted or crashes some how
@Override
public void onDestroy() {
    isServiceRunning = false;
    super.onDestroy();
}

@Override
public IBinder onBind(Intent intent) {
    // Used only in case of bound services.
    return null;
}


void startServiceWithNotification() {
    if (isServiceRunning) return;
    isServiceRunning = true;

    Intent notificationIntent = new Intent(getApplicationContext(), MyActivity.class);
    notificationIntent.setAction(C.ACTION_MAIN);  // A string containing the action name
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    PendingIntent contentPendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

    Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.my_icon);

    Notification notification = new NotificationCompat.Builder(this)
            .setContentTitle(getResources().getString(R.string.app_name))
            .setTicker(getResources().getString(R.string.app_name))
            .setContentText(getResources().getString(R.string.my_string))
            .setSmallIcon(R.drawable.my_icon)
            .setLargeIcon(Bitmap.createScaledBitmap(icon, 128, 128, false))
            .setContentIntent(contentPendingIntent)
            .setOngoing(true)
//                .setDeleteIntent(contentPendingIntent)  // if needed
            .build();
    notification.flags = notification.flags | Notification.FLAG_NO_CLEAR;     // NO_CLEAR makes the notification stay when the user performs a "delete all" command
    startForeground(NOTIFICATION_ID, notification);
}

void stopMyService() {
    stopForeground(true);
    stopSelf();
    isServiceRunning = false;
}
}

Puis je le lance avec

    Intent startIntent = new Intent(getApplicationContext(), MyService.class);
    startIntent.setAction(C.ACTION_START_SERVICE);
    startService(startIntent);

Veuillez noter que les deux constantes utilisées en tant qu'actions, il s'agit de chaînes qui doivent commencer par le nom du paquet.

12
Beppi's

IntentService

Utiliser IntentService n'est probablement pas la meilleure approche. Par défaut, IntentService s’arrête après le retour de onHandleIntent(Intent) et il n’ya plus de travail à faire (c’est-à-dire que la file d’attente est vide). Ceci est expliqué dans la documentation officielle de IntentService :

Lorsque toutes les demandes ont été traitées, IntentService s’arrête, vous ne devez donc pas appeler stopSelf ().

Dans votre cas, onHandleIntent(Intent) crée un thread mais revient tout de suite, ce qui le fait s'arrêter de lui-même.

Service + startForeground ()

L'utilisation d'une Service régulière en mode avant-plan devrait fonctionner aussi longtemps que ce service est exécuté sur un processus séparé. Pour cela, vous avez besoin de:

  1. Faites en sorte que onStartCommand() renvoie START_STICKY.
  2. Appelez la méthode pour afficher le droit de notification dans onCreate().
  3. Exécutez le service dans un processus séparé (à l'aide de Android:process=":something").

D'après l'article, il semble que vous ayez essayé certaines de ces étapes de manière isolée, mais que vous ne les ayez jamais toutes essayées en même temps. 

5
Mike Laren

Vous pouvez simplement appeler votre service dans votre méthode onStop () dans votre activité . Même lorsque l'utilisateur arrête l'application, le service sera toujours en cours d'exécution.

0