【问题标题】:App restarts rather than resumes应用程序重新启动而不是恢复
【发布时间】:2013-11-01 23:27:22
【问题描述】:

希望有人能帮我弄清楚,如果不是解决方案,至少是对行为的解释。

问题:

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

细节:

当您按下“启动器图标”时,应用程序会正常启动 - 也就是说,我假设会启动一个 Intent,其名称为您的第一个 Activity,操作为 android.intent.action.MAIN,类别为 android.intent.category.LAUNCHER。然而,情况并非总是如此:

在大多数设备上,如果您在应用程序已经运行后按下启动器图标,则该进程中当前正在运行的 Activity 将恢复(不是最初的 Activity)。它恢复的方式与您从操作系统菜单的“最近的任务”中选择它的方式相同。这是我希望在所有设备上的行为。

但是,在选定的其他设备上会出现不同的行为:

  • 在摩托罗拉 Xoom 上,当您按下启动器图标时,应用程序将始终启动初始启动 Activity,无论当前正在运行什么。我假设启动器图标总是启动“LAUNCHER”意图。

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

我已经阅读了许多听起来与我的问题相似的答案,但只是将android:alwaysRetainTaskState="true" 或在Activity 中使用launchMode="singleTop" 不是答案。

编辑:

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

【问题讨论】:

  • 这似乎是一个微不足道的问题,但您是否在 Xoom 的开发选项中将“不保留活动”设置为 true?
  • 不(我希望!:)) - 我已将每个活动的生命周期和后台活动记录为仍然可用(它们已停止 - 未销毁)。在操作系统再次开始第一个Activity 而不是恢复它们的情况下,操作系统似乎在它们上调用finish()
  • 如果您按下主页按钮,然后单击启动器图标,您可能知道恢复行为是 android 的默认行为。但是,如果您按后退按钮返回主屏幕,大多数手机都会完成()该应用程序。您用于退出应用程序的任何方法是否可能在不同设备上有所不同?您能否注销 onKeyUpEvent 以检查是否有些人没有奇怪地处理硬键/软键?
  • 不-我确定上述问题。使用 home 将应用程序置于后台(而不是返回,你是对的,它将完成() Activity)。在 Xoom 上可以从任务列表(只是不能从启动器)恢复应用程序,所以后台堆栈肯定没有被杀死。
  • 用赏金回答是解决问题中描述的问题的方法。将我自己的答案标记为“正确”,因为尽管有时问题是由启动器中的应用程序错误引起的(如他的回答中所述),但我的特定问题是由任务切换引起的。 这两个问题的解决方案都由他的解决方案解决。

标签: android android-lifecycle


【解决方案1】:

在我的 Cat s60 上,我在开发者选项中启用了“不保留活动”,再次禁用它可以让我在不丢失应用状态的情况下切换应用...

【讨论】:

  • 不知道怎么做,但这在我的设备上是开启的。
【解决方案2】:

我遇到了同样的问题,原因是:

(Kotlin 代码,在 MainActivity 中)

override fun onBackPressed() {
    finish()
}

所以当从我的 LoginActivity 导航到我的 MainActivity 时,我使用这个:

    val intent = Intent(this, MainActivity::class.java)
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
    startActivity(intent)

使用这些标志时,我的 MainActivity 中不必有 onBackPressed(),它会在单击后自然退出应用程序。当按下 Home 按钮并返回应用程序时,它不会重新启动。

【讨论】:

    【解决方案3】:

    为不知道如何在 Android 手机中编程和遇到此问题的人提供解决方案。 这主要是由于android版本的升级(只是我的假设)。升级后,您的所有应用程序都经过优化以使用更少的电池。但是,这反过来又会降低您的设备速度。

    如何解决

    转到设置>>应用程序>>应用程序设置(在屏幕上的任何位置查找设置标志 - 它在不同设备上有所不同)>>电池优化(或类似的选项[在此处输入图像描述][1]打开)> > 将所有应用程序移至“未优化”状态(必须手动逐一进行 - 在某些手机中可能是允许/禁止)。您的启动器应用程序需要“未优化”(在我的情况下是 Zen UI 启动器 - 我猜这是罪魁祸首 - 如果有时间,您可以尝试优化/不优化并重新启动不同的应用程序)。 现在重启你的手机。(无需重置数据/安全模式或任何麻烦)

    立即尝试多任务处理。 :) 现在按下启动器图标应该会导致当前任务被恢复。 :) 您的设备将变为不用担心电池,反正它会耗尽。

    【讨论】:

      【解决方案4】:

      这个解决方案对我有用:

          @Override
          public boolean onKeyUp(int keyCode, KeyEvent event) {
              if (keyCode == KeyEvent.KEYCODE_BACK) {
                  Intent startMain = new Intent(Intent.ACTION_MAIN);
                  startMain.addCategory(Intent.CATEGORY_HOME);
                  startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                  startActivity(startMain);
                  return false;
              }
              else
                  return super.onKeyUp(keyCode, event);
          }
      

      信用: I need to minimize the android application on back button click

      可能不适用于所有设备,但在按下后退按钮时成功创建主页按钮行为,从而停止活动而不是完成活动。

      【讨论】:

      • 有趣的技巧,但并没有解决上述问题。不过对于其他问题/疑问非常有用。
      • 后退按钮有一个特定的用途,用户希望后退按钮做它应该做的事情。以任何方式覆盖它都是错误的,在我看来,这是非常不专业的。
      【解决方案5】:

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

      【讨论】:

      • 确实,这对我也有用。我发现另一个 SO 问题的答案很有帮助:stackoverflow.com/a/21622266/293280。这写了不同类型的launchMode 值:inthecheesefactory.com/blog/…
      • 这个修复对我有用!不是在清单中添加的,而是在主活动类的活动属性中添加的。
      • @CalinVlasin 你能告诉我你是如何使用 launchMode 的吗?你把它放在哪里了?目前我有这样的问题,但它导致了问题:
      • 这也是我的问题。我认为这应该与接受的答案一起使用 (!isTaskRoot...
      【解决方案6】:

      这个问题在 2016 年仍然很重要。今天,一位 QA 测试人员报告了我的一个应用程序在 Android M 中重新启动而不是从股票启动器中恢复

      实际上,系统正在将启动的活动添加到当前的task-stack,但在用户看来好像发生了重新启动并且他们丢失了工作。顺序是:

      1. 从 Play 商店下载(或侧载 apk)
      2. 从 Play 商店对话框启动应用程序:出现活动 A [任务堆栈:A]
      3. 导航到活动 B [任务堆栈:A -> B]
      4. 按“主页”按钮
      5. 从应用程序抽屉启动应用程序:出现活动 A! [任务堆栈:A -> B -> A](用户可以按“返回”按钮从此处进入活动“B”)

      注意:通过 ADB 部署的调试 APK 不会出现此问题,仅在从 Play 商店下载或旁加载的 APK 中才会出现。在后一种情况下,来自步骤 5 的启动意图包含标志 Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT,但在调试情况下不包含。一旦应用程序从启动器冷启动,问题就会消失。我怀疑任务是用格式错误(更准确地说,非标准)的 Intent 播种的,这会阻止正确的启动行为,直到任务被完全清除。

      我尝试了各种activity launch modes,但这些设置与用户期望的标准行为相差太大:在活动 B 处恢复任务。请参阅页面底部guide to Tasks and Back Stack 中预期行为的以下定义在“开始任务”下:

      这种意图过滤器会导致 Activity 的图标和标签显示在应用程序启动器中,从而为用户提供一种启动 Activity 并在启动后随时返回到它创建的任务的方法。

      我发现this answer 是相关的,并将以下内容插入到我的根活动 (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;
          }
      

      更新:将此解决方案从解析意图标志转移到查询活动是否直接位于任务的根目录。意图标志很难预测和测试,有各种不同的方式来打开 MAIN Activity(从家里启动、从“向上”按钮启动、从 Play 商店启动等)

      【讨论】:

      • “一旦应用程序从启动器冷启动,问题就会消失。”这是最奇怪的部分,我也观察到了——在第一次启动后杀死应用程序,它又开始正常运行。这么奇怪的错误。感谢您如此彻底地分析它并提供解决方案。
      • 注意:您可以在最初清除该问题后再次重现该问题(通过您所描述的“冷启动”),方法是使用应用程序的 Google Play 页面中的“打开”,甚至如果您通过 Android Studio 安装了 APK。我发现这对于验证修复是否有效非常有用。
      • 很好的解释!
      • 感谢您的解释 :)
      • 很多应用都会出现这种情况。谷歌照片是我测试的主要照片。
      【解决方案7】:

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

      在三星设备以及使用自定义启动器/皮肤的其他制造商上,这是一个相对常见的问题。我还没有看到这个问题出现在一个普通的 Android 启动器上。

      基本上,应用程序实际上并没有完全重新启动,但是当启动器恢复应用程序时,您的启动 Activity 正在启动并添加到 Activity 堆栈的顶部。当您恢复应用程序并显示启动活动时,您可以通过单击后退按钮来确认是这种情况。然后,您应该会被带到您希望在恢复应用时显示的 Activity。

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

      这是我在初始/启动活动的 onCreate() 中所做的:

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

      【讨论】:

      • 到目前为止,这对我有用,到目前为止没有任何不良副作用。根据逻辑假设,我认为它没有理由无效。
      • 我认为这是处理这个错误的正确方法。为我工作。
      • 为我完成了这项工作,在大约 8 种不同的设备上进行了验证。非常感谢!
      • WOOOOOW 解决了我的问题,我在过去 2 小时内一直在寻找解决方法
      • 谢谢@starkej2。像魅力一样工作。
      【解决方案8】:

      对您的用户来说是无价的。即使在最近使用的应用程序列表中呆了数周后,它仍然是一份完美的简历。

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

      背景: 主要活动中尚未开始任务的应用程序使用的内存很容易回收。操作系统可以简单地使用传递给 onCreate 的原始包重新启动应用程序。但是,您可以添加到 onSaveInstanceState 中的原始捆绑包中,因此当您的应用程序被操作系统重新启动时,您可以恢复实例状态,并且对于应用程序是否重新启动或恢复没有人更明智。以经典的地图程序为例。用户移动到地图上的一个位置,然后按下主页键。两周后,这个地图应用程序仍然与 facebook、pandora 和 candy crush 一起出现在最近的应用程序列表中。操作系统不仅为最近使用的应用程序保存应用程序的名称,它还保存用于启动应用程序的原始包。然而,程序员已经对onSaveInstanceState 方法进行了编码,因此原始包现在包含构建应用程序所需的所有材料和信息,因此看起来它已恢复。

      示例: 将当前相机位置保存在 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 那样让您在数周内保持活力。你必须在两周后编写一份完美的简历。对于复杂的应用程序来说,这不是一件容易的事,但我们支持您并随时为您提供帮助。

      祝你好运

      【讨论】:

      • 这不是由于常见的内存问题或默认的“暂停状态”条件。我已经在许多设备上尝试过我的应用程序(有些内存大,有些内存低)。
      • 这就是你在 onPause 中保存持久数据的原因我已经尝试在我每天使用的手机上恢复我的应用程序长达两周,让我告诉你两周后 onCreate 方法被调用并且os 传入我保存在 onSaveSessionState 中的包,我使用包中的数据使我的活动与我离开时完全一样。所以距离我的回答只有三天,所以你不可能完成两周的测试。摘要:应用程序在后台可以随时关闭。
      • @danny117 我认为您对 Graeme 遇到的问题没有准确的理解
      • 我了解 Graeme 的问题。在某些设备上恢复应用调用 onCreate。听起来和我的 HTC EVO(姜饼)一模一样,它会杀死应用程序只是为了旋转屏幕。查看它说的文档,以便可以在 onCreate developer.android.com/reference/android/app/… 中恢复应用程序
      • @danny117 是正确的,但他遇到的问题与恢复应用程序时重新创建的单个活动无关(这是预期的),但正在启动错误的活动
      【解决方案9】:

      啊哈! (tldr; 见底部粗体陈述)

      我发现了问题……我想。

      所以,我将从一个假设开始。当您按下启动器时,它会启动默认的Activity,或者,如果由先前启动启动的Task 是打开的,它将把它带到前面。换句话说 - 如果您在导航的任何阶段创建新的 Task 和旧的 finish,启动器现在将不再恢复您的应用。

      如果这个假设是真的,我很确定这应该是一个错误,因为每个 Task 都在同一个进程中,并且与创建的第一个候选简历一样有效?

      我的问题是通过从几个Intents 中删除这些标志来解决的:

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

      虽然很明显FLAG_ACTIVITY_NEW_TASK 创建了一个新的Task,但我不明白上述假设是否有效。我确实认为这是罪魁祸首并将其删除以进行测试,但我仍然遇到问题,因此我将其驳回。但是,我仍然有以下情况:

      i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
      

      我的初始屏幕使用上述标志在我的应用程序中启动“主”Activity。毕竟,如果我“重启”了我的应用程序并且Activity 仍在运行,我宁愿保留它的状态信息。

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

      如果设置,并且正在启动的活动已经在 当前任务,而不是启动该任务的新实例 活动,除此之外的所有其他活动都将关闭,并且 此 Intent 将作为 新意图。

      例如,考虑一个由以下活动组成的任务:A、B、C、D。 如果 D 调用 startActivity() 的 Intent 解析为 活动 B 的组成部分,然后 C 和 D 将完成,B 收到 给定的 Intent,导致堆栈现在是:A,B。

      上例中当前正在运行的活动 B 实例将 要么接收您从这里开始的新意图 onNewIntent() 方法,或者自己完成并使用新的重新启动 意图。如果它已将其启动模式声明为“多重”( 默认值)并且您没有设置 FLAG_ACTIVITY_SINGLE_TOP 相同 意图,然后它将完成并重新创建;对于所有其他发射 模式或者如果设置了 FLAG_ACTIVITY_SINGLE_TOP 那么这个 Intent 将是 传递到当前实例的 onNewIntent()。

      这种启动模式也可以配合使用效果很好 FLAG_ACTIVITY_NEW_TASK:如果用于启动任务的根活动, 它将将该任务的任何当前正在运行的实例带到 前台,然后将其清除为根状态。这尤其 有用,例如,在从通知启动活动时 经理。

      所以,我遇到了如下描述的情况:

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

      在这个阶段,第二个FLAG_ACTIVITY_CLEAR_TOP 标志正在重新启动任务堆栈中的B。我假设这必须破坏Task 并开始一个新的,导致我的问题,如果你问我,这是一个非常难以发现的情况!

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

      • Launcher 只恢复最初创建的任务
      • FLAG_ACTIVITY_CLEAR_TOP 将在重新启动唯一剩余的Activity 时,还会重新创建一个新的Task

      【讨论】:

      • FLAG_ACTIVITY_CLEAR_TOP 不会创建新任务或重新启动您尝试启动的 Activity(如果它是唯一剩余的 Activity)。 “如果设置了,并且正在启动的活动已经在当前任务中运行,那么不会启动该活动的新实例,而是关闭它上面的所有其他活动,并且此 Intent 将被传递到(现在顶部)作为新意图的旧活动。”
      • 我意识到这并不意味着 - 但通过反复试验,这恰好是我的例子。删除这些标志可以解决问题。
      • 这并不能在所有条件下在所有设备上创建完美的简历。
      • 删除标志为我解决了这个问题。谢谢
      • 我确实有启动画面/主屏幕场景,但我没有使用任何标志来从启动画面过渡到主屏幕,但问题对我来说仍然是可重现的 - 这个解决方案对我不起作用。跨度>
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-08
      • 2021-01-04
      • 2011-12-08
      • 2020-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多