NavUtils.navigateUpTo()不启动任何活动

我有两个活动

  • MainActivity
  • DeepLinkActivity

我build立了一切使用NavUtils来导航像这里和这里build议的这里 。

我想要达到的是:

  1. 通过深层链接启动DeepLinkActivity
  2. 向上压
  3. 转到MainActivity

只要在最近的应用程序中有我的应用程序的任何任务,一切都很好。

但是,当我从最近的应用程序中删除我的应用程序时,它的行为如下所示:

  1. 从最近的应用程序中清除我的应用程序
  2. 通过深层链接启动DeepLinkActivity
  3. 向上压
  4. 我的应用程序closures,就像按下后

我debugging了代码,发现NavUtils.shouldUpRecreateTask()返回falseupIntent一切设置为正常,像我的Component设置。 但是, NavUtils.navigateUpTo()行为就像调用finish() 。 没有日志声明,什么都没有

任何想法,如何解决?

AndroidManifest.xml中

 <activity android:name=".DeepLinkActivity" android:parentActivityName="my.package.MainActivity"> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value="my.package.MainActivity"/> <intent-filter> <!-- Some intent filter --> </intent-filter> </activity> 

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); } } 

—–编辑—–

我意识到,几个Google Apps都以同样的方式被破坏。 如果你跳转到例如search联系人,在AB按下,你会发现自己在主屏幕上,而不是联系人的应用程序。 (API19 / CM11)

我认为这种方法是错误的。 我已经阅读了支持库源代码,并检查了意图的行为。 它只适用于您的应用程序以前创build..正如你所描述的,如果你从应用程序预览中杀了它,shouldUp方法停止工作。

我已经用我自己的“shouldUpRecreateTask”解决了这个问题。 当我收到一个直接创build一个Activity的Notification(就像你的行为一样),我从BroadCastReceiver发送一个自定义Action到intent中。 然后,在我的方法中,我做下一件事:

 private final boolean shouldUpRecreateTask(Activity from){ String 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); } 

我对OPs问题的解决scheme:

 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); } } 

如果DeepLinkActivity是任务的根, isTaskRoot()将返回true(应用程序或应用程序的初始启动之前已通过任务pipe理器终止)。 这样,当应用程序任务已经在前台时,如果活动是通过链接启动的,则不会丢失现有的后退堆栈。

它看起来像NavUtils.shouldUpRecreateTask(this, upIntent)不准备这个特殊情况。

我当前的解决方法是检查,如果Activity是深度链接,并强迫这样的情况下一个新的任务堆栈。

就我而言,我在内部传递EXTRA的对象。 但是如果Activity是从外部开始的,则通过跟踪指向特定URL的链接或通过触摸感知NFC的设备来设置ACTIONUri

 @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); } } 

你是否使用<activity-alias>作为你的MAIN / LAUNCHER? 当我将<activity-alias>更改为<activity> ,向上导航正常工作。 出于某种奇怪的原因,当涉及到别名时,导航不能正常工作。

还有一个奇怪的UI故障,表明本机ActivityManager有一个错误。 使用navigateUpTo()导航到应用程序的主要活动后,按设备的后退键。 当前的应用程序将执行活动退出animation,然后紧接着,下一个最近的应用程序也将执行活动退出animation。 即使您从Android的主屏幕启动到当前应用程序,也会发生这种情况。 如果您清除所有最近使用的应用程序并再次尝试导航后退步骤,则在退出animation过程中将出现随机(即意外)应用程序。

其他应用程序不应该在这些情况下呈现。 看起来活动pipe理器似乎没有正确pipe理历史堆栈。

在下面的方法中可以find有问题的错误:

 + public boolean navigateUpTo(IBinder token, Intent destIntent, int resultCode, + Intent resultData) { + ComponentName dest = destIntent.getComponent(); + + synchronized (this) { + ActivityRecord srec = ActivityRecord.forToken(token); + ArrayList<ActivityRecord> 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; + } + } 

我发现以下为我工作。 如果“活动”与其他活动或通知深入链接,则会在您向上导航时创build堆栈,而这些活动只是展现在前面。

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

只要你有

 android:parentActivityName="parent.activity" 

在你的清单

这对我也不起作用。 所以我这样处理:

  @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); } 

我的MainActivity被标记为android清单中的singleTask

 android:launchMode="singleTask" 

如果你从一个通知去你的活动,你将不得不创build通知时创build堆栈,检出这个答案: Navitils.shouldUpRecreateTask失败的果冻豆

尝试这个 :

 @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; }