应用程序重新启动,而不是恢复

希望有人可以帮我弄清楚,如果不是解决scheme,至less可以解释一个行为。

问题:

在某些设备上,按下启动器图标会导致当前任务被恢复,而在其他设备上导致启动初始意图被启动(有效地重新启动应用程序)。 为什么会发生?

细节:

当你按下“启动器图标”的应用程序启动正常 – 也就是说,我认为,一个意图启动您的第一个Activity的名称与行动android.intent.action.MAIN和类别android.intent.category.LAUNCHER 。 但是,这并不总是如此:

在大多数设备上,如果在应用程序已经运行之后按下启动程序图标,则该进程中当前正在运行的Activity被恢复( 不是初始Activity )。 它的恢复方式与您从OS菜单中的“Recent Tasks”(近期任务)中select相同。 这是我想在所有设备上的行为。

但是,在选定的其他设备上会发生不同的行为

  • 在Motorola Xoom上,当您按下启动器图标时,应用程序将始终启动初始启动Activity而不pipe当前正在运行的是什么。 我假设启动器图标总是启动“LAUNCHER”的意​​图。

  • 在Samsung Tab 2上,按下启动器图标时,如果您刚刚安装了应用程序,它将始终启动初始Activity (与Xoom相同) – 但是,在安装后重新启动设备后,启动器图标将会而是恢复应用程序。 我假设这些设备在设备启动时将“安装的应用程序”添加到查找表中,允许启动器图标正确恢复正在运行的任务?

我读过许多类似于我的问题的声音 ,但只是简单地添加android:alwaysRetainTaskState="true"或使用launchMode="singleTop"Activity不是答案。

编辑:

在最近发布这个应用程序之后,我们发现这个行为在第一次重启之后已经开始在所有设备上发生。 这对我来说似乎很疯狂,但通过重新启动过程,我实际上找不到发生了什么问题。

您遇到的行为是由于API 1以后的某些Android启动器中存在的问题引起的。您可以在此处find有关该错误的详细信息以及可能的解决scheme: https : //code.google.com/p/android/issues/详细信息?id = 2373 。

这是三星设备以及使用自定义启动器/皮肤的其他制造商相对常见的问题。 我没有看到这个问题发生在股票Android启动器上。

基本上,应用程序实际上并没有完全重启,但是启动Activity正在启动,并在启动器恢复应用程序时将其添加到Activity堆栈的顶部。 您可以通过点击后退button确认这种情况,当您恢复应用程序,并显示启动活动。 然后,您应该将其带到您恢复应用程序时预期显示的活动。

我select实施解决此问题的解决方法是在启动初始活动的意图中检查Intent.CATEGORY_LAUNCHER类别和Intent.ACTION_MAIN操作。 如果这两个标记都存在,并且活动不在任务的根(意味着应用程序已经运行),那么我在最初的Activity上调用finish()。 确切的解决scheme可能不适合你,但类似的应该。

以下是我在onCreate()中执行的初始/启动活动:

  if (!isTaskRoot() && getIntent().hasCategory(Intent.CATEGORY_LAUNCHER) && getIntent().getAction() != null && getIntent().getAction().equals(Intent.ACTION_MAIN)) { finish(); return; } 

这个问题在2016年仍然相关。今天一个QAtesting人员报告了一个重启矿的应用程序,而不是 Android M 的股票发射器中恢复。

实际上,系统正在将已启动的活动添加到当前的任务堆栈中 ,但对用户来说似乎已经发生了重启,并且他们已经失去了工作。 序列是:

  1. 从Play商店下载(或sideload apk)
  2. 从Play商店对话框启动应用程序:活动A出现[任务堆栈:A]
  3. 导航到活动B [任务堆栈:A – > B]
  4. 按“主页”button
  5. 从应用程序抽屉启动应用程序:活动A出现! [任务堆栈:A – > B – > A](用户可以按'Back'button从这里到达活动'B')

注意:通过ADB部署的debuggingAPK不会显示此问题,只有在从Play商店下载的APK或侧面加载的APK中。 在后一种情况下,来自步骤5的启动意图包含标志Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT ,但不包含在debugging案例中。 一旦应用程序从发射器冷启动,问题就消失。 我的怀疑是任务种子格式不正确(更准确,非标准),意图阻止正确的启动行为,直到完全清除任务。

我尝试了各种活动启动模式 ,但是这些设置与用户期望的标准行为偏离太多:在活动B处恢复任务。请参阅页面底部“ 任务和返回堆栈 ” 指南中的预期行为的以下定义在“启动任务”下:

这种意图filter会在应用程序启动器中显示活动的图标和标签,为用户提供一种启动活动并返回到启动后任何时间创build的任务的方式。

我发现这个答案是相关的,并将以下内容插入到我的根活动(A)的“onCreate”方法中,以便在用户打开应用程序时能够适当地恢复。

  /** * Ensure the application resumes whatever task the user was performing the last time * they opened the app from the launcher. It would be preferable to configure this * behavior in AndroidMananifest.xml activity settings, but those settings cause drastic * undesirable changes to the way the app opens: singleTask closes ALL other activities * in the task every time and alwaysRetainTaskState doesn't cover this case, incredibly. * * The problem happens when the user first installs and opens the app from * the play store or sideloaded apk (not via ADB). On this first run, if the user opens * activity B from activity A, presses 'home' and then navigates back to the app via the * launcher, they'd expect to see activity B. Instead they're shown activity A. * * The best solution is to close this activity if it isn't the task root. * */ if (!isTaskRoot()) { finish(); return; } 

更新:从parsing意图标志移动此解决scheme,以查询活动是否直接在任务的根源。 意图标志很难预测和testing所有不同的方式来打开一个MAIN活动(从家里启动,从“上”button启动,从Play商店启动等)

啊哈! (tldr;见底部粗体的语句)

我发现了这个问题…我想。

所以,我会以一个假设开始。 当您按下启动器时,它会启动默认的“ Activity或者,如果上一次启动的“ Task已打开,则会将其带到最前面。 换句话说 – 如果在导航的任何阶段你创build一个新的Taskfinish旧的Task ,发射器现在不会再恢复你的应用程序。

如果这个假设是真的,我敢肯定,这应该是一个错误,因为每个Task都在同一个过程中,并且与第一个创build的候选人一样有效。

我的问题,然后,通过从几个Intents删除这些标志是固定的:

 i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK ); 

虽然很明显FLAG_ACTIVITY_NEW_TASK创build了一个新的Task ,但我并不理解上述假设是有效的。 我确实认为这是一个罪魁祸首,并将其删除,我仍然有一个问题,所以我驳回了它。 但是,我仍然有以下的条件:

 i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) 

我的启animation面是在我的应用程序中使用上面的标志开始“主” Activity 。 毕竟,如果我“重新启动”我的应用程序, Activity仍在运行,我宁愿保留它的状态信息。

你会注意到在文档中没有提到开始一个新的Task

如果已设置,并且正在启动的活动已在当前任务中运行,则不会启动该活动的新实例,而是closures其上的所有其他活动,并将此Intent交付给(现在开启顶端)旧活动作为一个新的意图。

例如,考虑一个由以下活动组成的任务:A,B,C,D。如果D调用startActivity(),并将Intentparsing为活动B的组件,则C和D将完成,B接收给定的Intent ,导致堆栈现在是:A,B。

在上面的例子中,当前正在运行的活动B的实例将会在onNewIntent()方法中接收到你从这里开始的新的意图,或者自己完成并重新启动新的意图。 如果它已经声明它的启动模式是“多个”(默认),并且你没有在同一个意图中设置FLAG_ACTIVITY_SINGLE_TOP,那么它将被完成和重新创build; 对于所有其他启动模式,或者如果设置了FLAG_ACTIVITY_SINGLE_TOP,则这个Intent将被传递到当前实例的onNewIntent()。

这个启动模式也可以和FLAG_ACTIVITY_NEW_TASK结合使用:如果用来启动一个任务的根活动,它将会把当前正在运行的那个任务的实例带到前台,然后清除它的根状态。 例如,从通知pipe理器启动活动时,这是特别有用的。

所以,我的情况如下:

  • A带有FLAG_ACTIVITY_CLEAR_TOP A启动B完成。
  • B希望重新启动服务,因此将用户发送到具有服务重新启动逻辑和UI(无标志)的A
  • A与FLAG_ACTIVITY_CLEAR_TOP, A启动B完成。

在这个阶段,第二个FLAG_ACTIVITY_CLEAR_TOP标志正在重启任务堆栈中的B 我假设这必须摧毁Task并开始一个新的,造成我的问题,这是一个非常困难的情况,如果你问我!

所以,如果我所有的假设都是正确的:

  • Launcher只恢复最初创build的任务
  • 如果FLAG_ACTIVITY_CLEAR_TOP重新启动剩下的唯一Activity ,则重新创build一个新的Task

我在三星设备上遇到同样的问题。 经过大量search,这些答案都没有为我工作。 我发现在AndroidManifest.xml文件中, launchMode设置为singleInstanceandroid:launchMode="singleInstance" )。 删除launchMode属性解决了我的问题。

无价给你的用户。 甚至在最近使用的应用程序列表中坐了几个星期后,完美的简历

它看起来像一个简历给用户,但实际上是一个完整的开始。

背景:主要活动中尚未启动任务的应用所使用的内存很容易回收。 操作系统可以简单地重新启动应用程序与传递到onCreate的原始包。 但是,您可以添加到onSaveInstanceState的原始包,所以当您的应用程序由操作系统重新启动时,您可以恢复实例状态,没有人更聪明应用程序是否重新启动或恢复。 以经典地图程序为例。 用户移动到地图上的位置,然后按下主页键。 两周后,这个地图应用程序仍然在facebook,潘多拉和糖果粉碎的最近的应用程序列表。 操作系统不仅保存最近使用的应用程序的应用程序的名称,还保存用于启动应用程序的原始包。 然而,程序员已经编写了onSaveInstanceState方法,所以orignal包现在包含构build应用程序所需的所有材料和信息,所以它看起来像被恢复了。

示例:保存当前摄像头在onSaveInstanceState中的位置,只是在应用程序被卸载并且必须在几周后从最近的应用列表重新启动。

 @Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); // save the current camera position; if (mMap != null) { savedInstanceState.putParcelable(CAMERA_POSITION, mMap.getCameraPosition()); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // get the exact camera position if the app was unloaded. if (savedInstanceState != null) { // get the current camera position; currentCameraPosition = savedInstanceState .getParcelable(CAMERA_POSITION); } 

注意:您也可以使用onRestoreInstanceState方法,但是我发现在onCreate恢复实例更容易。

这很可能是你的应用程序正在发生的事情。 在某些设备上,您的应用程序被卸载以释放内存。 是的,有一些标志,但标志不会拿起你的应用程序的每一个细微差异,这些标志不会让你像onSaveInstanceState一样活着几周。 你必须在两个星期后编写完整的简历。 对于复杂的应用程序来说,这不是一件容易的事情,但是我们在你身后,并且在这里提供帮助。

祝你好运