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
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);
}
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.
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.
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:
onStartCommand()
renvoie START_STICKY
.onCreate()
.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.
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.