【问题标题】:How to get combined behaviour of FLAG_ACTIVITY_CLEAR_TOP and FLAG_ACTIVITY_CLEAR_TASK?如何获得 FLAG_ACTIVITY_CLEAR_TOP 和 FLAG_ACTIVITY_CLEAR_TASK 的组合行为?
【发布时间】:2015-01-26 12:20:25
【问题描述】:

与此相关的 SO 有很多问题,但我找不到这样直接的问题。

我的应用有一个主活动 M 和一个子活动 S。

M launchModesingleTask,因为我只想运行一个实例,并且我希望 S 与 M 存在于同一任务中。

S launchModestandard,因为它可以有很多实例。

在 S 中,有一个向上按钮,必须始终将用户带到 M。

有两种类型的任务堆栈(S在顶部):

  1. MSSSS...S

如果用户在 S 中按下 Up,那么堆栈应该变成:

M(其中 M 应该处于用户离开它的相同状态)

  1. SSSS...S

如果用户在 S 中按下 Up,那么堆栈应该变成:

M(一个新实例)

--

那么如何为向上按钮构造Intent...

在第一种情况下,FLAG_ACTIVITY_CLEAR_TOP 应该可以解决问题,但如果我们将此应用于第二种情况,则用户将被转储回主页。

在第二种情况下,FLAG_ACTIVITY_CLEAR_TASK 可以解决问题,但如果我们将其应用于第一种情况,我们会发现 M 已完成并重新启动。

人们也可能想尝试FLAG_ACTIVITY_NEW_TASK,但我们发现从 M 中点击 Back 会将用户带到他/她点击 Up 的屏幕。

旁注:当 M 为 singleTask 并且所有活动都具有相同的(默认)任务关联时,这怎么可能?

那么在这种情况下如何正确构造Up Intent呢?

【问题讨论】:

  • 你有很多S但没有M是什么情况?为什么M 完成了?这让一切变得更加困难。您应该检查您的应用程序架构,看看您是否可以让M 在任务堆栈中保持活动状态。然后,您可能可以摆脱所有活动的标准启动模式,只需使用标志来确保在根目录下有一个 M 实例
  • 简单地说 S 也是一个潜在的切入点 - 例如从一个小部件。在那种情况下,使用 M 作为转发活动感觉就像是一个重大黑客攻击。

标签: android android-intent android-activity android-task


【解决方案1】:

你不能构造一个 UP Intent 来做你想做的事。这些东西是相互排斥的。您可以执行以下操作:

M的启动模式改为singleTop

M.onCreate() 中,使用isTaskRoot() 检查M 是否位于任务的根目录。如果不是任务根,请让M 自行重启并清除任务,如下所示:

Intent relaunch = new Intent(this, M.class);
relauch.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(relaunch);

在您的 UP Intent 中,添加以下标志:Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP

这将确保如果任务中已经存在M 的实例,它将清除该实例之上的所有内容并在现有实例上调用onNewIntent()

如果任务中没有M 的现有实例,它将在堆栈顶部启动一个新实例。该实例将识别出它不是根 Activity,它会清除任务并重新启动自身。

注意:这仅适用于 Android 3.0 及更高版本(API 11 或更高版本)。

【讨论】:

  • 谢谢!但是,使用 singleTop,如何停止 M 的多个实例?
  • 一般来说,您不会创建多个实例。如果你这样做了,你在onCreate() 中的代码将确保任务被清除回原来的M。使用此代码,您最终不可能在活动堆栈中拥有超过 1 个 M 的活动实例。
  • 通常你不需要使用特殊的启动模式“singleTask”或“singleInstance”。使用这些启动模式通常会产生比它解决的问题更多的问题,使用它们的人通常不知道他们为什么要这样做。不惜一切代价避免。
  • 是的,标准启动模式在这种情况下也应该可以工作。
【解决方案2】:

这是使用(Lollipop)已弃用 API 的解决方法/hack:

ActivityManager am = (ActivityManager)getSystemService(ACTIVITY_SERVICE);
if (M_CLASS_NAME.equals(am.getRunningTasks(1).get(0).baseActivity.getClassName()) {
    // we should be able to just clear top - because M is already running
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
}
else {
    // okay to assume M is not running (because it is always root of task)
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
}

【讨论】:

    猜你喜欢
    • 2016-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多