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

时间:2013-10-23 15:24:24

标签: android android-lifecycle

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

问题:

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

详细信息:

按下"启动器图标"应用程序正常启动 - 也就是说,我假设,使用行为Activity和类别android.intent.action.MAIN启动了一个名为第一个android.intent.category.LAUNCHER的Intent。然而,情况总是如此:

在大多数设备上,如果您在应用程序运行后按下启动器图标,则会恢复该进程中当前运行的活动(初始Activity)。它的恢复方式与您从" Recent Tasks"中选择的方式相同。在OS菜单中。这是我想要所有设备的行为。

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

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

  • 在Samsung Tab 2上,当您按下启动器图标时,如果您刚刚安装了应用程序,它将始终启动初始Activity(与Xoom相同) - 但是,重启后安装后的设备,启动器图标将恢复应用程序。我假设这些设备添加了#34;已安装的应用程序"进入设备启动时的查找表,允许启动器图标正确恢复正在运行的任务?

我已经阅读了许多与我的问题类似的声音的答案,但只是将android:alwaysRetainTaskState="true"launchMode="singleTop"添加到Activity并不是答案

修改

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

9 个答案:

答案 0 :(得分:193)

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

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

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

我选择实现解决此问题的解决方法是检查启动初始Activity的intent中的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;
    }

答案 1 :(得分:46)

这个问题在2016年仍然具有现实意义。今天,QA测试人员报告了我的应用程序重启而不是从Android M中的股票启动器恢复

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

  1. 从Play商店下载(或侧载apk)
  2. 从Play商店对话框启动应用:活动A出现 [任务堆栈:A]
  3. 导航到活动B [任务堆栈:A - > B]
  4. 按“主页”按钮
  5. 从应用抽屉启动应用:活动A出现! [任务堆栈:A - > B - > A](用户可以按“返回”按钮从此处进入活动'B')
  6. 注意:此问题并不表示通过ADB部署的调试APK,仅在从Play商店下载或侧载的APK中。在后一种情况下,步骤5中的启动意图包含标志Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT,但不包含在调试情况中。一旦应用程序从启动器冷启动,问题就消失了。我怀疑是任务是一个格式错误(更准确,非标准)的Intent,它会阻止正确的启动行为,直到完全清除任务。

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

      

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

    我发现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;
        }
    

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

答案 2 :(得分:14)

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

我发现了问题......我想。

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

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

我的问题是通过从几个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)

我的启动画面正在启动&#34;主要&#34;使用上述标记在我的应用中Activity。毕竟,如果我有&#34;重启&#34;我的应用程序和Activity仍在运行,我宁愿保留它的状态信息。

您会在documentation中注意到它没有提及开始新的Task

  

如果设置,则正在启动的活动已在运行中   当前任务,然后而不是启动它的新实例   活动,其上的所有其他活动将被关闭   这个意图将作为一个传递到(现在在顶部)旧活动   新的意图。

     

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

     

上例中活动B的当前运行实例将会   要么接收你从这里开始的新意图   onNewIntent()方法,或者自己完成并重新使用new   意图。如果它已宣布其启动模式为&#34;多个&#34; (该   默认情况下,您没有设置FLAG_ACTIVITY_SINGLE_TOP   意图,然后它将完成并重新创建;所有其他发射   模式或如果设置了FLAG_ACTIVITY_SINGLE_TOP,那么此Intent将是   传递到当前实例的onNewIntent()。

     

此启动模式也可用于与之配合使用   FLAG_ACTIVITY_NEW_TASK:如果用于启动任务的根活动,   它会将任何当前正在运行的任务实例带到   前景,然后将其清除到其根状态。这是特别的   例如,从通知启动活动时很有用   管理器。

所以,我的情况如下所述:

  • A使用B FLAG_ACTIVITY_CLEAR_TOP启动AB完成。
  • A希望重新启动服务,然后将用户发送到具有服务重启逻辑的A 和UI(无标志)。
  • B使用FLAG_ACTIVITY_CLEAR_TOP启动AFLAG_ACTIVITY_CLEAR_TOP完成。

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

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

  • FLAG_ACTIVITY_CLEAR_TOP仅恢复最初创建的任务
  • Activity,如果重新启动剩余的Task,还会重新创建新的{{1}}

答案 3 :(得分:6)

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

答案 4 :(得分:0)

这个解决方案对我有用:

    @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 :(得分:0)

在Cat s60上,我已在“开发人员”选项中启用了“不保留活动”,再次禁用此功能使我可以在不丢失应用程序状态的情况下切换应用程序...

答案 6 :(得分:-1)

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

如何解决

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

立即尝试多任务。 :) 现在,按下启动器图标将导致当前任务恢复。 :) 您的设备将变为“不用担心电池”,它仍然会耗尽。

答案 7 :(得分:-1)

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

(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(),它将在单击时自然退出该应用程序。而且,当按下主屏幕按钮并返回到应用程序时,它不会重新启动。

答案 8 :(得分:-6)

对您的用户无价。即使在最近使用的应用程序列表中待了几周之后,也是完美的简

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

<强>背景 主要活动中尚未启动任务的应用程序使用的内存很容易回收。操作系统可以简单地重新启动应用程序,并将原始包传递给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那样让你活着好几周。你必须在两周后的简历中编写完美的代码。对于复杂的应用程序来说,这不是一件容易的事,但是我们支持你,并且随时为你提供帮助。

祝你好运