Tout d'abord, je sais qu'il ne faut pas vraiment tuer / redémarrer une application sur Android. Dans mon cas d'utilisation, je souhaite réinitialiser mon application en usine dans un cas spécifique où un serveur envoie des informations spécifiques au client.
L'utilisateur ne peut être connecté sur le serveur qu'avec UNE seule instance de l'application (c'est-à-dire que plusieurs appareils ne sont pas autorisés). Si une autre instance obtient ce verrou "connecté", toutes les autres instances de cet utilisateur doivent supprimer leurs données (réinitialisation d'usine), pour maintenir la cohérence.
Il est possible d'obtenir de force le verrou, car l'utilisateur pourrait supprimer l'application et la réinstaller, ce qui entraînerait un identifiant d'instance différent et l'utilisateur ne pourrait plus libérer le verrou. Par conséquent, il est possible d'obtenir de force le verrou.
En raison de cette possibilité de force, nous devons toujours vérifier dans un cas concret qu'il a le verrou. Cela se fait sur (presque) chaque requête au serveur. Le serveur peut envoyer un "identifiant de verrouillage incorrect". Si cela est détecté, l'application cliente doit tout supprimer.
C'était le cas d'utilisation.
J'ai un Activity
A qui démarre le Login Activity
L ou le Activity
B principal de l'application en fonction d'une valeur sharedPrefs. Après avoir démarré L ou B, il se ferme de sorte que seul L ou B fonctionne. Donc, dans le cas où l'utilisateur est déjà connecté, B s'exécute maintenant.
B commence C. C appelle startService
le IntentService
D. Cela se traduit par cette pile:
(A)> B> C> D
À partir de la méthode onHandleIntent de D, un événement est envoyé à un ResultReceiver R.
R gère désormais cet événement en fournissant à l'utilisateur une boîte de dialogue où il peut choisir de réinitialiser l'application en usine (supprimer la base de données, sharedPrefs, etc.)
Après la réinitialisation d'usine, je veux redémarrer l'application (pour fermer toutes les activités) et redémarrer uniquement A qui lance ensuite la connexion Activity
L et se termine:
(A)> L
La méthode onClick de la boîte de dialogue ressemble à ceci:
@Override
public void onClick(DialogInterface dialog, int which) {
// Will call onCancelListener
MyApplication.factoryReset(); // (Deletes the database, clears sharedPrefs, etc.)
Intent i = new Intent(MyApp.getContext(), A.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MyApp.getContext().startActivity(i);
}
Et c'est la MyApp
classe:
public class MyApp extends Application {
private static Context context;
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
public static Context getContext() {
return context;
}
public static void factoryReset() {
// ...
}
}
Le problème est que si j'utilise les FLAG_ACTIVITY_NEW_TASK
activités B et C sont toujours en cours d'exécution. Si je clique sur le bouton de retour sur la connexion, Activity
je vois C, mais je veux revenir à l'écran d'accueil.
Si je ne règle pas, FLAG_ACTIVITY_NEW_TASK
j'obtiens l'erreur:
07-07 12:27:12.272: ERROR/AndroidRuntime(9512): android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
Je ne peux pas utiliser les activités Context
, car le ServiceIntent
D peut également être appelé à partir d'une tâche d'arrière-plan qui est lancée par le AlarmManager
.
Alors, comment pourrais-je résoudre cela pour que la pile d'activités devienne (A)> L?