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?
la source
Vous pouvez simplement appeler:
Qui est utilisé dans la bibliothèque ProcessPhoenix
Comme alternative:
Voici une version un peu améliorée de la réponse @Oleg Koshkin.
Si vous voulez vraiment redémarrer votre activité, y compris l'arrêt du processus en cours, essayez de suivre le code. Placez-le dans une HelperClass ou là où vous en avez besoin.
Cela réinitialisera également les classes jni et toutes les instances statiques.
la source
AlarmManager
et se comportent mal si vous utilisez cette solution. Une meilleure approche?Jake Wharton a récemment publié sa bibliothèque ProcessPhoenix , qui le fait de manière fiable. Vous n'avez qu'à appeler:
La bibliothèque terminera automatiquement l'activité d'appel, tuera le processus de demande et redémarrera ensuite l'activité d'application par défaut.
la source
<category android:name="android.intent.category.DEFAULT" />
à votre activité par défaut <intent-filter> dans le manifeste de l'application.J'ai légèrement modifié la réponse Ilya_Gazman pour utiliser de nouvelles API (IntentCompat est déconseillé à partir de l'API 26). Runtime.getRuntime (). Exit (0) semble être meilleur que System.exit (0).
la source
System.exit(n)
est effectivement équivalent à l'appel:Runtime.getRuntime().exit(n)
". En interne,System.exit()
se retourne et appelleRuntime.getRuntime().exit()
. Il n'y a rien de "meilleur" dans l'un ou l'autre (sauf si l'on se préoccupe de la quantité de frappe que l'on fait ou d'une couche supplémentaire d'appels de méthode).Runtime.getRuntime().exit(0)
(ouSystem.exit(0)
) fonctionneront probablement. Certains de mes " mauvais commentaires" sont des réponses (comme celle d' Ilya Gazman qui a depuis été modifiée pour incorporer un tel appel.IntentCompat.makeRestartActivityTask
La nouvelle façon de procéder consiste à utiliser IntentCompat.makeRestartActivityTask
la source
Application
objet. Par conséquent, toutes lesstatic
données, données initialisées lors de la création desApplication
classes, ou jni restent dans leur état actuel et ne sont pas réinitialisées.IntentCompat.makeRestartActivityTask
est désormais obsolète . Si vous inspectez le code source , c'est aussi simple que d'ajouter simplement des indicateursIntent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
.Il y a un truc vraiment sympa. Mon problème était qu'une bibliothèque jni C ++ vraiment ancienne avait perdu des ressources. À un moment donné, il a cessé de fonctionner. L'utilisateur a tenté de quitter l'application et de la relancer - sans résultat, car terminer une activité n'est pas la même chose que terminer (ou tuer) le processus. (Soit dit en passant, l'utilisateur pourrait accéder à la liste des applications en cours d'exécution et l'arrêter à partir de là - cela fonctionnerait, mais les utilisateurs ne savent tout simplement pas comment mettre fin aux applications.)
Si vous souhaitez observer l'effet de cette fonctionnalité, ajoutez une
static
variable à votre activité et incrémentez-la chacune, par exemple, appuyez sur le bouton. Si vous quittez l'activité d'application, puis appelez à nouveau l'application, cette variable statique conservera sa valeur. (Si l'application était vraiment fermée, la variable se verrait attribuer la valeur initiale.)(Et je dois expliquer pourquoi je ne voulais pas corriger le bogue à la place. La bibliothèque a été écrite il y a des décennies et des fuites de ressources depuis. La direction pense que cela a toujours fonctionné . Le coût de la fourniture d'un correctif au lieu d'une solution de contournement ... Je pense que vous avez l'idée.)
Maintenant, comment pourrais-je réinitialiser une bibliothèque partagée jni (aka dynamic, .so) à son état initial? J'ai choisi de redémarrer l'application en tant que nouveau processus.
L'astuce est que System.exit () ferme l'activité en cours et Android recrée l'application avec une activité de moins.
Le code est donc:
L'activité appelante exécute simplement le code
MagicAppRestart.doRestart(this);
, l'activité appelanteonPause()
est exécutée, puis le processus est recréé. Et n'oubliez pas de mentionner cette activité dans AndroidManifest.xmlL'avantage de cette méthode est qu'il n'y a pas de retards.
UPD: cela fonctionnait dans Android 2.x, mais dans Android 4 quelque chose a changé.
la source
System.exit(0)
parandroid.os.Process.killProcess(android.os.Process.myPid());
? 2) une boucle infinie signifie très probablement qu'ils ne suppriment pas l'activité la plus élevée lorsqu'ils redémarrent une application. En principe, vous pouvez ajouter une variable booléenne statique, la définir sur true avant d'appeler l'activité de redémarrage et après le redémarrage, elle sera fausse. Ainsi, l'activité peut savoir si le redémarrage a déjà eu lieu (et si cela s'est produit, il suffit de terminer () ). OTOH, votre rapport signifie que l'astuce ne fonctionne pas de manière identique sur tous les appareils.Ma solution ne redémarre pas le processus / l'application. Il permet uniquement à l'application de "redémarrer" l'activité à domicile (et de rejeter toutes les autres activités). Cela ressemble à un redémarrage pour les utilisateurs, mais le processus est le même. Je pense que dans certains cas, les gens veulent obtenir cet effet, alors je laisse juste ici FYI.
la source
Ok, j'ai refactorisé mon application et je ne terminerai pas A automatiquement. Je laisse cette course toujours et la termine tout au long de l'
onActivityResult
événement. De cette façon, je peux utiliser les drapeauxFLAG_ACTIVITY_CLEAR_TOP
+FLAG_ACTIVITY_NEW_TASK
pour obtenir ce que je veux:et dans le
ResultReceiver
Merci quand même!
la source
la source
Le seul code qui n'a pas déclenché «Votre application s'est fermée de façon inattendue» est le suivant. C'est également du code non obsolète qui ne nécessite pas de bibliothèque externe. Il ne nécessite pas non plus de minuterie.
la source
J'ai constaté que cela fonctionne sur l'API 29 et versions ultérieures - dans le but de tuer et de redémarrer l'application comme si l'utilisateur l'avait lancée alors qu'elle n'était pas en cours d'exécution.
Cela a été fait lorsque l'activité du lanceur dans l'application a ceci:
J'ai vu des commentaires affirmant qu'une catégorie de DEFAUT est nécessaire, mais je n'ai pas trouvé que c'était le cas. J'ai confirmé que l'objet Application dans mon application est recréé, donc je crois que le processus a vraiment été tué et redémarré.
Le seul but pour lequel j'utilise ceci est de redémarrer l'application après que l'utilisateur a activé ou désactivé les rapports de plantage pour Firebase Crashlytics. Selon leurs documents, l'application doit être redémarrée (processus tué et recréé) pour que cette modification prenne effet.
la source
La meilleure façon de redémarrer complètement une application est de la relancer, pas seulement de passer à une activité avec
FLAG_ACTIVITY_CLEAR_TOP
etFLAG_ACTIVITY_NEW_TASK
. Donc ma solution est de le faire depuis votre application ou même depuis une autre application, la seule condition est de connaître le nom du package de l'application (exemple: ' com.example.myProject ')Exemple de redémarrage d'utilisation ou de lancement de appA à partir de appB :
Vous pouvez vérifier si l'application est en cours d'exécution:
Remarque : je sais que cette réponse est un peu hors sujet, mais elle peut être très utile pour quelqu'un.
la source
Ma meilleure façon de redémarrer l'application est d'utiliser
finishAffinity();
Depuis,
finishAffinity();
ne peut être utilisé que sur les versions JELLY BEAN, donc nous pouvons utiliserActivityCompat.finishAffinity(YourCurrentActivity.this);
pour les versions inférieures.Ensuite, utilisez
Intent
pour lancer la première activité, de sorte que le code ressemblera à ceci:J'espère que ça aide.
la source
Essayez d'utiliser
FLAG_ACTIVITY_CLEAR_TASK
la source
Voici un exemple pour redémarrer votre application de manière générique à l'aide du PackageManager:
la source
Application
objet. Par conséquent, les données statiques, les données initialisées lors de la création desApplication
classes ou jni restent dans leur état actuel et ne sont pas réinitialisées.essaye ça:
la source
Démarrez directement l'écran initial avec
FLAG_ACTIVITY_CLEAR_TASK
etFLAG_ACTIVITY_NEW_TASK
.la source
J'ai dû ajouter un gestionnaire pour retarder la sortie:
la source
Utilisation:
Cela fonctionne à partir du niveau 16 (4.1) de l'API, je crois.
la source
Vous pouvez utiliser la
startInstrumentation
méthode deActivity
. Vous devez implémenter videInstrumentation
et pointé dans le manifeste. Après cela, vous pouvez appeler cette méthode pour redémarrer votre application. Comme ça:J'obtiens le nom de classe d'Instrumentation dynamiquement mais vous pouvez le coder en dur. Certains aiment ça:
Appelez
startInstrumentation
pour recharger votre application. Lisez la description de cette méthode. Mais il peut être dangereux de se comporter comme une application de mise à mort.la source
L'application sur laquelle je travaille doit donner à l'utilisateur la possibilité de choisir les fragments à afficher (les fragments sont modifiés dynamiquement au moment de l'exécution). La meilleure solution pour moi était de redémarrer complètement l'application.
J'ai donc essayé de nombreuses solutions et aucune d'entre elles n'a fonctionné pour moi, mais ceci:
En espérant que cela va aider quelqu'un d'autre!
la source
essaye ça:
la source
Avec la bibliothèque Process Phoenix . L'activité que vous souhaitez relancer s'appelle "A".
Saveur Java
Saveur de kotlin
la source
Vous pouvez redémarrer votre activité actuelle comme ceci:
Fragment:
Activité:
la source