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

存在的问题:

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

细节:

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

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

然而,在选定的其他设备上,会发生不同的行为:

On the Motorola Xoom, when you press the launcher icon, the App will always start the initial launch Activity regardless of what is currently running. I assume that the launcher icons always start the "LAUNCHER" intent. On the Samsung Tab 2, when you press the launcher icon, if you have just installed the app, it will always launch the initial Activity (Same as the Xoom) - however, after you restart the device after the install, the launcher icon will instead resume the app. I assume that these devices add "installed apps" into a lookup table on device startup which allow the launcher icons to correctly resume running tasks?

我读过很多答案,听起来类似于我的问题,但简单地添加android:alwaysRetainTaskState="true"或使用launchMode="singleTop"的活动不是答案。

编辑:

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


啊哈!(tldr;请参阅底部粗体的语句)

我发现问题了……我认为。

我先从一个假设开始。当你按下启动器时,它会启动默认的Activity,或者,如果之前启动的Task是打开的,它会把它带到前面。换句话说,如果在导航的任何阶段,你创建了一个新的任务,并完成了旧的任务,启动器现在将不再继续你的应用程序。

如果这个假设是正确的,我很确定这应该是一个错误,因为每个任务都在同一个过程中,并且与创建的第一个任务一样是有效的简历候选人。

然后,我的问题通过从几个intent中删除这些标志来解决:

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

虽然很明显FLAG_ACTIVITY_NEW_TASK创建了一个新Task,但我没有意识到上面的假设是有效的。我确实认为这是一个罪魁祸首,并将其移除进行测试,但我仍然有问题,所以我驳回了它。但是,我仍然具备以下条件:

i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)

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

你会注意到在文档中没有提到启动一个新任务:

If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent. For example, consider a task consisting of the activities: A, B, C, D. If D calls startActivity() with an Intent that resolves to the component of activity B, then C and D will be finished and B receive the given Intent, resulting in the stack now being: A, B. The currently running instance of activity B in the above example will either receive the new intent you are starting here in its onNewIntent() method, or be itself finished and restarted with the new intent. If it has declared its launch mode to be "multiple" (the default) and you have not set FLAG_ACTIVITY_SINGLE_TOP in the same intent, then it will be finished and re-created; for all other launch modes or if FLAG_ACTIVITY_SINGLE_TOP is set then this Intent will be delivered to the current instance's onNewIntent(). This launch mode can also be used to good effect in conjunction with FLAG_ACTIVITY_NEW_TASK: if used to start the root activity of a task, it will bring any currently running instance of that task to the foreground, and then clear it to its root state. This is especially useful, for example, when launching an activity from the notification manager.

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

A用FLAG_ACTIVITY_CLEAR_TOP启动B, A结束。 B希望重新启动服务,因此将用户发送给具有服务重新启动逻辑的a 和UI(没有标志)。 A以FLAG_ACTIVITY_CLEAR_TOP启动B, A结束。

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

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

启动程序只恢复最初创建的任务 FLAG_ACTIVITY_CLEAR_TOP如果重新启动唯一剩下的Activity,也会重新创建一个新的Task


对你的用户来说是无价的。完美的简历,即使在最近使用的应用程序列表中坐了几个星期。

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

Background: The memory used by apps that are in the main activity that haven't started a task is easy to reclaim. The os can simply restart the app with the original bundle passed to onCreate. You can however add to the original bundle in onSaveInstanceState so when your app is restarted by the OS you can restore the instance state and no one is the wiser on whether the app restarted or resumed. Take for example the classic map program. The user moves to a position on the map and then presses the home key. Two weeks later this mapping app is still in the list of recent apps along with facebook, pandora, and candy crush. The OS doesn't just save the name of the app for the recently used apps it also saves the original bundle used to start the app. However the programmer has coded the onSaveInstanceState method so the orignal bundle now contains all the materials and information necessary to construct the app so it looks like it was resumed.

例子: 保存当前相机的位置在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那样活几个星期。你必须在两周后写出一份完美的简历。对于复杂的应用程序来说,这不是一项简单的任务,但我们支持你,并在这里提供帮助。

祝你好运


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

在三星设备和其他使用自定义启动器/皮肤的制造商上,这是一个相对常见的问题。我还没见过这个问题发生在普通的Android启动器上。

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

为了解决这个问题,我选择的解决方法是检查Intent。CATEGORY_LAUNCHER类别和意图。ACTION_MAIN意图中启动初始Activity的动作。如果这两个标志是存在的,活动不是在任务的根(意味着应用程序已经在运行),然后我调用finish()在初始活动。这个确切的解决方案可能不适合你,但类似的方法应该适用。

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

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

        finish();
        return;
    }

这个问题在2016年仍然有意义。今天,一名QA测试人员报告说,我的一个应用程序在Android M中重新启动,而不是从库存启动器恢复。

实际上,系统正在将已启动的活动添加到当前任务堆栈中,但在用户看来,好像发生了重新启动,他们丢失了工作。顺序是:

从play store下载(或旁载apk) 从play store对话框启动应用程序:出现活动A[任务堆栈:A] 导航到活动B[任务堆栈:A -> B] 按“Home”键 从应用程序抽屉中启动应用程序:出现活动A ![任务堆栈:A -> B -> A](用户可以按“后退”键从这里进入活动“B”)

Note: this problem does not manifest for debug APK's deployed via ADB, only in APKs downloaded from the Play Store or side-loaded. In the latter cases, the launch intent from step 5 contained the flag Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT, but not in the debug cases. The problem goes away once the the app has been cold-started from the launcher. My suspicion is the Task is seeded with a malformed (more accurately, non-standard) Intent that prevents the correct launch behavior until the task is cleared entirely.

我尝试了各种活动启动模式,但这些设置偏离了用户期望的标准行为:在活动b中恢复任务。在“开始一个任务”页面底部的“任务和Back Stack”中,可以看到以下预期行为的定义:

这种意图过滤器会在应用程序启动器中显示活动的图标和标签,使用户可以启动活动,并在活动启动后随时返回到它所创建的任务。

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

UPDATE:将这个解决方案从解析意图标志移到查询活动是否直接位于任务的根。意图标志很难预测和测试所有打开MAIN活动的不同方式(从home启动,从“向上”按钮启动,从Play Store启动等)。


我在三星设备上也遇到了同样的问题。经过一番搜索,这些答案没有一个对我有用。我发现在AndroidManifest.xml文件中,launchMode被设置为singleInstance (android:launchMode="singleInstance")。删除launchMode属性修复了我的问题。


这个解决方案对我很有效:

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

信贷: 我需要最小化android应用程序的后退按钮点击

可能不能在所有设备上工作,但当返回按钮被按下时,会成功地创建home键行为,从而停止活动而不是结束活动。


解决方案的人谁不知道编程和遇到这个问题在他们的android手机。 这主要是由于android版本的升级(只是我的假设)。升级后,你所有的应用程序都优化为使用更少的电池。但是,这反过来会降低你的设备速度。

如何解决

Go to settings>>Apps>>apps settings(look for settings sign anywhere on the screen- it is different on different devices)>>battery optimization(or similar opti[enter image description here][1]on)>> move all apps to 'not optimised' state (have to do 1 by 1 manually -may be allow/disallow in some phones). Your launcher app need to be 'not optimised'(Zen UI launcher in my case - this is the culprit I guess- you could try optimising/Not optimizing and restarting different app if you have time). Now restart your phone. (no need to reset data/safe mode or any trouble)

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


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

(Kotlin代码,在MainActivity中)

override fun onBackPressed() {
    finish()
}

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

    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键并返回应用程序时,它不会重新启动。


在我的Cat s60上,我在开发者选项中启用了“不要保留活动”,再次禁用这个选项可以让我在不失去应用程序状态的情况下切换应用程序……