Force l’application à redémarrer sur la première activité

Pour une raison inconnue, je ne parviens pas à laisser mon application partir correctement pour que, lorsque j’appuie à nouveau sur le bouton d’accueil et l’icône de l’application, je reprenne ma position dans l’application. Je voudrais forcer l’application à redémarrer sur la première activité.

Je suppose que cela a quelque chose à voir avec onDestroy () ou peut-être onPause () mais je ne sais pas quoi faire.

Voici un exemple pour redémarrer votre application de manière générique en utilisant le PackageManager:

Intent i = getBaseContext().getPackageManager() .getLaunchIntentForPackage( getBaseContext().getPackageName() ); i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(i); 

La solution marquée comme «réponse» fonctionne mais présente un inconvénient qui était critique pour moi. Avec FLAG_ACTIVITY_CLEAR_TOP, votre activité cible sera appelée onCreate avant que votre ancienne stack d’activités ne reçoive onDestroy. Pendant que je nettoyais des choses nécessaires dans onDestroy, je devais travailler.

C’est la solution qui a fonctionné pour moi:

 public static void restart(Context context, int delay) { if (delay == 0) { delay = 1; } Log.e("", "restarting app"); Intent restartIntent = context.getPackageManager() .getLaunchIntentForPackage(context.getPackageName() ); PendingIntent intent = PendingIntent.getActivity( context, 0, restartIntent, Intent.FLAG_ACTIVITY_CLEAR_TOP); AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); manager.set(AlarmManager.RTC, System.currentTimeMillis() + delay, intent); System.exit(2); } 

L’idée est de déclencher un PendingIntent via AlarmManager qui sera appelé un peu plus tard, donnant à l’ancienne stack d’activité le temps de s’éclaircir.

si vous voulez toujours commencer à la racine que vous voulez définir Android: clearTaskOnLaunch à true sur votre activité root

 android:clearTaskOnLaunch="true" android:launchMode="singleTask" 

Utilisez cette propriété dans le fichier manifeste dans la classe de début (première activité).

FLAG_ACTIVITY_CLEAR_TOP fait-il ce que vous devez faire?

 Intent i = new Intent(getBaseContext(), YourActivity.class); i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(i); 

La réponse de Marc fonctionne très bien, sauf dans mon cas où mon activité principale est un mode de lancement de singleTop. Une fois que je lance cette intention, puis navigue vers de nouvelles activités et appuie sur le bouton d’accueil de l’appareil, puis relance mon application à partir de l’icône de l’application, je crée une nouvelle instance de l’activité principale avec mon activité précédente .

Selon cette question, c’est parce que les intentions ne correspondent pas. En adb dumpsys activity , je vois que depuis mon lanceur Android standard, le paquet est nul alors que, comme le suggère Marc, le paquet intent est le nom de mon paquet. Cette différence les empêche de correspondre et de démarrer une nouvelle instance lorsque l’icône de l’application est à nouveau appuyée et que l’activité principale n’est pas au top.

Cependant, sur d’autres lanceurs, comme sur le Kindle, le package est défini en fonction de l’intention du lanceur, il me fallait donc un moyen générique de gérer les lanceurs. J’ai ajouté des méthodes statiques telles que:

 static boolean mIsLaunchIntentPackageNull = true; public static boolean isLaunchIntent(Intent i) { if (Intent.ACTION_MAIN.equals(i.getAction()) && i.getCategories() != null && i.getCategories().contains(Intent.CATEGORY_LAUNCHER)) { return true; } return false; } public static void handleLaunchIntent(Intent i) { if (isLaunchIntent(i)) { if (i.getPackage() != null) { mIsLaunchIntentPackageNull = false; } else { mIsLaunchIntentPackageNull = true; } } } 

avec un mécanisme comme celui-ci:

  Intent intentHome = appContext.getPackageManager() .getLaunchIntentForPackage( appContext.getPackageName()); intentHome.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // need to match launcher intent exactly to avoid duplicate activities in stack if (mIsLaunchIntentPackageNull) { intentHome.setPackage(null); } appContext.startActivity(intentHome); 

puis dans l’activité principale définie dans mon manifeste, j’ai ajouté cette ligne:

 public void onCreate(Bundle savedInstanceState) { [class from above].handleLaunchIntent(getIntent()); 

Cela fonctionne pour moi sur Kindle et mon téléphone, et me permet de réinitialiser correctement l’application sans append une autre instance de l’activité principale.

FLAG_ACTIVITY_CLEAR_TOP ne fonctionnait pas pour moi car je devais supporter 2.3.3. Ma première solution était:

 Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()); intent.addFlags(Build.VERSION.SDK_INT >= 11 ? Intent.FLAG_ACTIVITY_CLEAR_TASK : Intent.FLAG_ACTIVITY_CLEAR_TOP); context.startActivity(intent); 

Cela fonctionne presque, mais pas tout à fait.

Comme j’ai une activité de base, j’ai ajouté une émission de mise à mort qui ferme toutes mes activités en cours.

 public abstract class BaseActivity extends AppCompatActivity { private static final Ssortingng ACTION_KILL = "BaseActivity.action.kill"; private static final IntentFilter FILTER_KILL; static { FILTER_KILL = new IntentFilter(); FILTER_KILL.addAction(ACTION_KILL); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); registerReceiver(killReceiver, FILTER_KILL); } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(killReceiver); } private final BroadcastReceiver killReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { finish(); } }; public void killApp(){ sendBroadcast(new Intent(ACTION_KILL)); } } 

Toutes mes activités s’étendent de cette classe, donc

 ((BaseActivity)getActivity()).killApp(); startActivity(new Intent(getActivity(), StartActivity.class)); 

redémarre l’application. Testé sur genymotion v10, v16, v21 et Nexus 5 avec v22.

Edit: ceci ne supprime pas une activité si elle est détruite au moment de l’envoi de l’intention. Je cherche toujours une solution.

Le code suivant fonctionne pour moi, il peut redémarrer l’application complète parfaitement!

 Intent mStartActivity = new Intent(context, StartActivity.class); int mPendingIntentId = 123456; PendingIntent mPendingIntent = PendingIntent.getActivity(context,mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT); AlarmManager mgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent); System.exit(0); 

cela a fonctionné pour moi:

 Intent mStartActivity = new Intent(ctx.getApplicationContext(), ActivityMain.class); mStartActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); mStartActivity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) mStartActivity.addFlags(0x8000); // equal to Intent.FLAG_ACTIVITY_CLEAR_TASK int mPendingIntentId = 123456; PendingIntent mPendingIntent = PendingIntent.getActivity(ctx, mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT); AlarmManager mgr = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE); mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, mPendingIntent); ActivityManager manager = (ActivityManager) ctx.getApplicationContext().getSystemService(ctx.getApplicationContext().ACTIVITY_SERVICE); List activityes = ((ActivityManager)manager).getRunningAppProcesses(); ((Activity)ctx).moveTaskToBack(true); manager.killBackgroundProcesses("com.yourpackagename"); System.exit(0); 

Vous pouvez utiliser la lib ProcessPhoenix de Jake Wharton pour redémarrer votre processus d’application.

Après avoir bien réfléchi et testé, j’ai enfin trouvé le moyen d’appeler mon activité à recréer lorsque l’application est restée avec le bouton d’accueil:

 android:clearTaskOnLaunch 

dans le manifeste

 @Override public void onRestart(){ onCreate(); } 

Cela fait l’affaire … (mieux que lorsqu’il est mis en onResume qui est appelé chaque fois que vous lancez l’application, même la première fois, provoquant un double affichage)