NavUtils.navigateUpTo () ne démarre aucune activité

J’ai deux activités

  • MainActivity
  • DeepLinkActivity

J’ai tout configuré pour utiliser les NavUtils pour naviguer comme conseillé ici , ici et ici .

Ce que je veux réaliser c’est:

  1. Démarrez DeepLinkActivity via un lien profond
  2. Appuyez sur
  3. Aller à MainActivity

Tout fonctionne bien tant qu’il y a une tâche de mon application dans les applications récentes.

Cependant, lorsque je retire mon application des applications récentes, elle se comporte comme ceci:

  1. Éliminer mon application des applications récentes
  2. Démarrez DeepLinkActivity via un lien profond
  3. Appuyez sur
  4. Mon application se ferme, comme lorsque vous appuyez sur

J’ai débogué le code et découvert que NavUtils.shouldUpRecreateTask() renvoie false . upIntent a tout défini comme normal, comme mon jeu de Component . Mais NavUtils.navigateUpTo() même, NavUtils.navigateUpTo() se comporte comme un appel à finish() . Aucune déclaration de journal, rien.

Des idées pour réparer celà?

AndroidManifest.xml

       

DeepLinkActivity.java

 @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case android.R.id.home: Intent upIntent = NavUtils.getParentActivityIntent(this); if (NavUtils.shouldUpRecreateTask(this, upIntent)) { // create new task TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent) .startActivities(); } else { // Stay in same task NavUtils.navigateUpTo(this, upIntent); } return true; default: return super.onOptionsItemSelected(item); } } 

—– Modifier —–

Je me suis rendu compte que quelques applications Google sont brisées de la même manière. Si vous sautez par exemple sur Contacts depuis la recherche, appuyez sur AB et vous vous retrouverez sur l’écran d’accueil au lieu de l’application Contacts. (API19 / cm11)

    Je pense que cette méthode est bogue. J’ai lu le code source de la bibliothèque de support et cette méthode vérifie l’action de l’intention. Cela ne fonctionne que lorsque votre application a déjà été créée .. comme vous l’avez décrit, si vous la supprimez de l’aperçu des applications, la méthode shouldUp ne fonctionnera plus.

    J’ai corrigé ceci en utilisant mon propre “shouldUpRecreateTask”. Lorsque je reçois une notification qui crée directement une activité (comme votre comportement), j’envoie depuis mon BroadCastReceiver une action personnalisée dans l’intention. Ensuite, dans ma méthode, je fais la chose suivante:

     private final boolean shouldUpRecreateTask(Activity from){ Ssortingng action = from.getIntent().getAction(); return action != null && action.equals(com.xxxxxx.activities.Intent.FROM_NOTIFICATION); } 

    ……………………..

      if (shouldUpRecreateTask(this)) { TaskStackBuilder.create(this) .addNextIntentWithParentStack(upIntent) .startActivities(); } else { fillUpIntentWithExtras(upIntent); NavUtils.navigateUpTo(this, upIntent); } 

    Ma solution au problème des OP:

     public void navigateUp() { final Intent upIntent = NavUtils.getParentActivityIntent(this); if (NavUtils.shouldUpRecreateTask(this, upIntent) || isTaskRoot()) { Log.v(logTag, "Recreate back stack"); TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent).startActivities(); } else { NavUtils.navigateUpTo(this, upIntent); } } 

    isTaskRoot() renverra true si DeepLinkActivity est la racine d’une tâche (le lancement initial de l’application ou de l’application a déjà été interrompu par le biais du gestionnaire de tâches). De cette façon, je ne perds pas la stack de sauvegarde existante si une activité était lancée via un lien lorsque la tâche des applications était déjà au premier plan.

    Il semble que NavUtils.shouldUpRecreateTask(this, upIntent) ne soit pas préparé pour ce cas particulier.

    Ma solution de contournement actuelle consiste à vérifier si l’ Activity était profondément liée et à forcer une nouvelle stack de tâches pour de tels cas.

    Dans mon cas, je fais circuler des objects en EXTRA interne. Mais un ACTION et un Uri sont définis si l’ Activity est lancée depuis l’extérieur en suivant un lien vers une URL spécifique ou en touchant des périphériques compatibles NFC.

     @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case android.R.id.home: Intent upIntent = NavUtils.getParentActivityIntent(this); if (NavUtils.shouldUpRecreateTask(this, upIntent) || getIntent().getAction() != null) { // deep linked: force new stack // create new task TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent) .startActivities(); } else { // Stay in same task NavUtils.navigateUpTo(this, upIntent); } return true; default: return super.onOptionsItemSelected(item); } } 

    Utilisez-vous un comme votre MAIN / LAUNCHER? Lorsque je change le en , la navigation ascendante fonctionne correctement. Pour des raisons étranges, la navigation ne fonctionne pas correctement lorsque des alias sont impliqués.

    Il y a aussi un petit problème d’interface utilisateur qui indique que le fichier ActivityManager natif a un bogue. Après avoir navigateUpTo() jusqu’à l’activité principale de l’application à l’aide de navigateUpTo() , appuyez sur la touche Retour du périphérique. L’application actuelle exécutera l’animation de sortie d’activité puis, immédiatement après, l’application la plus récente effectuera également une animation de sortie d’activité. Cela se produit même si vous avez lancé dans l’application actuelle à partir de l’écran d’accueil d’Android. Si vous effacez toutes les applications récentes et réessayez les étapes de navigation, une application aléatoire (inattendue) sera présentée lors de l’animation de sortie.

    Les autres applications ne doivent jamais être présentées dans ces cas. Il semble que le gestionnaire d’activité ne gère pas correctement la stack d’historique.

    Le bug incriminé peut être trouvé dans la méthode suivante qui apparaît au bas de ce diff :

     + public boolean navigateUpTo(IBinder token, Intent destIntent, int resultCode, + Intent resultData) { + ComponentName dest = destIntent.getComponent(); + + synchronized (this) { + ActivityRecord srec = ActivityRecord.forToken(token); + ArrayList history = srec.stack.mHistory; + final int start = history.indexOf(srec); + if (start < 0) { + // Current activity is not in history stack; do nothing. + return false; + } + int finishTo = start - 1; + ActivityRecord parent = null; + boolean foundParentInTask = false; + if (dest != null) { + TaskRecord tr = srec.task; + for (int i = start - 1; i >= 0; i--) { + ActivityRecord r = history.get(i); + if (tr != r.task) { + // Couldn't find parent in the same task; stop at the one above this. + // (Root of current task; in-app "home" behavior) + // Always at least finish the current activity. + finishTo = Math.min(start - 1, i + 1); + parent = history.get(finishTo); + break; + } else if (r.info.packageName.equals(dest.getPackageName()) && + r.info.name.equals(dest.getClassName())) { + finishTo = i; + parent = r; + foundParentInTask = true; + break; + } + } + } + + if (mController != null) { + ActivityRecord next = mMainStack.topRunningActivityLocked(token, 0); + if (next != null) { + // ask watcher if this is allowed + boolean resumeOK = true; + try { + resumeOK = mController.activityResuming(next.packageName); + } catch (RemoteException e) { + mController = null; + } + + if (!resumeOK) { + return false; + } + } + } + final long origId = Binder.clearCallingIdentity(); + for (int i = start; i > finishTo; i--) { + ActivityRecord r = history.get(i); + mMainStack.requestFinishActivityLocked(r.appToken, resultCode, resultData, + "navigate-up"); + // Only return the supplied result for the first activity finished + resultCode = Activity.RESULT_CANCELED; + resultData = null; + } + + if (parent != null && foundParentInTask) { + final int parentLaunchMode = parent.info.launchMode; + final int destIntentFlags = destIntent.getFlags(); + if (parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE || + parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK || + parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP || + (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) { + parent.deliverNewIntentLocked(srec.app.uid, destIntent); + } else { + try { + ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo( + destIntent.getComponent(), 0, UserId.getCallingUserId()); + int res = mMainStack.startActivityLocked(srec.app.thread, destIntent, + null, aInfo, parent.appToken, null, + 0, -1, parent.launchedFromUid, 0, null, true, null); + foundParentInTask = res == ActivityManager.START_SUCCESS; + } catch (RemoteException e) { + foundParentInTask = false; + } + mMainStack.requestFinishActivityLocked(parent.appToken, resultCode, + resultData, "navigate-up"); + } + } + Binder.restoreCallingIdentity(origId); + return foundParentInTask; + } + } 

    J’ai trouvé ce qui suit travaillé pour moi. Si l’activité était profondément liée à une autre activité ou si une notification était créée, la stack serait créée au fur et à mesure que vous avanciez, les activités sont simplement mises en avant.

     case android.R.id.home: Intent upIntent = NavUtils.getParentActivityIntent(this); upIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); startActivity(upIntent); finish(); return true; 

    A condition d’avoir

     android:parentActivityName="parent.activity" 

    dans votre manifeste

    Ça ne marche pas pour moi aussi. Donc je me débrouille comme ça:

      @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { Intent intent = new Intent(this, MainActivity.class); startActivity(intent); finish(); return true; } return super.onOptionsItemSelected(item); } 

    Mon MainActivity est marqué comme singleTask dans le manifeste Android

     android:launchMode="singleTask" 

    Si vous accédez à votre activité à partir d’une notification, vous devez créer la stack lors de la création de la notification, en extrayant cette réponse: NavUtils.shouldUpRecreateTask échoue sur JellyBean

    Essaye ça :

     @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case android.R.id.home: Intent upIntent = NavUtils.getParentActivityIntent(this); if (NavUtils.shouldUpRecreateTask(this, upIntent)) { // create new task TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent) .startActivities(); } else { // Stay in same task NavUtils.navigateUpTo(this, upIntent); } break; default: return super.onOptionsItemSelected(item); } return true; } 

    Essayez la réponse suivante en travaillant pour moi dans les deux cas, démarrez l’activité à partir de la notification et démarrez une activité à partir de l’activité parent.

     @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: Intent upIntent = NavUtils.getParentActivityIntent(this); if (NavUtils.shouldUpRecreateTask(this, upIntent) || isTaskRoot()) { TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent) .startActivities(); } else { finish(); } return true; default: return super.onOptionsItemSelected(item); } }