341 votes

HOWTO programatically « redémarrer » application android ?

Tout d'abord, je sais que l'on ne devrait pas vraiment tuer/redémarrer une Application sur Android. Dans mon cas d'utilisation que je veux en usine réinitialiser mon application dans un cas particulier où un serveur envoie une information spécifique pour le client. L'utilisateur peut uniquement être connecté sur le serveur avec UNE seule instance de l'application (i.e. plusieurs dispositifs ne sont pas autorisés). Si une autre instance obtient que "connecté"-verrouiller toutes les autres instanecs de l'utilisateur pour supprimer leurs données (factory-reset), en raison de la cohérence. Il est possible de forcer pour obtenir le verrou, car l'utilisateur peut supprimer l'application et de la réinstaller ce qui pourrait donner lieu à une instance-id et l'utilisateur n'a pas pu libérer le verrou plus. Par conséquent, il est possible de forcer pour obtenir le verrou.

En raison de cette force-possibilité nous devons toujours vérifier dans un des cas concrets qu'il a de la serrure. Qui est fait sur (presque) chaque requête au serveur. Le serveur peut envoyer un "mal-lock-id". Si c'est détecté, l'application cliente doit tout effacer.


C'était le cas d'utilisation. Pas pour la mise en œuvre-question:

J'ai un Activity Un qui commence le Login Activity L ou les applications principales Activity B selon un sharedPrefs champ. Après le démarrage de L ou B, il se ferme de lui-même, de sorte que seul L ou B est en cours d'exécution. Ainsi, dans le cas où l'utilisateur est déjà connecté, B est actuellement en cours.

B commence à C. C des appels startService de la IntentService D. Que les résultats de cette pile:

(A) > B > C > D

à partir de la onHandleIntent méthode de D un événement est envoyé à un ResultReceiver R.

R, qui gère aujourd'hui le cas échéant, de fournir à l'utilisateur une boîte de dialogue dans laquelle il peut choisir d'usine réinitialiser l'application (supprimer db, sharedPrefs etc.)

Après la factory-reset, je veux redémarrer l'application (pour fermer toutes les activités) et seulement de commencer Un nouveau qui se lance ensuite le Login Activity L et des finitions de lui-même:

(A) > L

Les boîtes de dialogue onClick méthode ressemble à ceci:

@Override
public void onClick(DialogInterface dialog, int which) {
    // will call onCancelListener
    MyApplication.factoryReset(); // (deletes db, 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 l' 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 maintenant est que si j'utilise l' FLAG_ACTIVITY_NEW_TASK les Activités B et C sont toujours en cours d'exécution. Si j'ai frappé à l'arrière btn sur la page d' Activity je vois C, mais je veux revenir à l'écran d'Accueil. Si je n'aime pas mettre la 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, parce que l' ServiceIntent D pourrait également être appelée à partir d'une tâche de fond qui est démarré par l' AlarmManager.

Alors, comment pourrais-je résoudre ce à l'activité de la pile devient: (A) > L ?

320voto

Oleg Koshkin Points 666

Vous pouvez utiliser `` pour lancer votre activité de démarrage à l’avenir et à la fermeture de votre application de configuration

129voto

mikepenz Points 1258

Voici une version améliorée de bit de @Oleg Koshkin réponse.

Si vous voulez redémarrer votre activité, y compris une mise à mort du processus en cours, essayez de code suivant. Placez-le dans un HelperClass ou où vous en avez besoin.

Cela réinitialise également jni classes et toutes les instances statiques.

28voto

Il est vraiment une bonne affaire. Mon problème est que certains de vraiment vieux C++ jni bibliothèque de fuite de ressources. À un certain moment, il a cessé de fonctionner. L'utilisateur a essayé de quitter l'application et la relancer, sans résultat, parce que la finition d'une activité n'est pas la même que la finition (ou tuer) le processus. (En passant, l'utilisateur peut accéder à la liste des applications en cours d'exécution et l'arrêter à partir de là, ce serait le travail, mais les utilisateurs ne sais pas comment faire pour mettre fin à des applications.)

Si vous voulez observer l'effet de cette fonction, ajoutez une static variable pour de votre activité et de l'incrémenter à chaque, dire, appuyez sur le bouton. Si vous quittez l'application d'activité puis d'appeler à nouveau l'application, cette variable statique gardera sa valeur. (Si la demande était vraiment quitté, la variable serait affecté de la valeur initiale.)

(Et je dois dire pourquoi je n'ai pas envie de corriger le bug à la place. La bibliothèque a été écrite il y a des décennies et des fuites de ressources depuis. La direction croit qu'il a toujours travaillé. Le coût de fournir un correctif à la place d'une solution de contournement... je pense que vous obtenez l'idée.)

Maintenant, comment pourrais-je réinitialiser un jni partagé (un.k.un. dynamique, .donc) de la bibliothèque à l'état initial? J'ai choisi de redémarrer l'application comme un nouveau processus.

Le truc, c'est que le Système.exit() ferme l'activité et Android recrée l'application avec une activité de moins en moins.

Donc le code est:

/** This activity shows nothing; instead, it restarts the android process */
public class MagicAppRestart extends Activity {
    // Do not forget to add it to AndroidManifest.xml
    // <activity android:name="your.package.name.MagicAppRestart"/>
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        System.exit(0);
    }
    public static void doRestart(Activity anyActivity) {
        anyActivity.startActivity(new Intent(anyActivity.getApplicationContext(), MagicAppRestart.class));
    }
}

La vocation de l'activité juste exécute le code MagicAppRestart.doRestart(this);, la vocation de l'activité de l' onPause() est exécutée, puis le processus est re-créé. Et n'oubliez pas de mentionner cette activité dans AndroidManifest.xml

L'avantage de cette méthode est qu'il n'y a pas de retard.

16voto

Stuck Points 2206

OK, j’ai refait mon application et je ne vais pas finir A automatiquement. J’ai laisser courir toujours et finir par le événement. De cette façon je peux utiliser le + `` drapeaux pour obtenir ce que je veux :

et dans le``

Merci quand même !

13voto

Nirav Ranpara Points 5859
Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage( getBaseContext().getPackageName() );
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X