【问题标题】:Launching an Activity within a certain fragment, then going back to the previous Activity from where it was launched?在某个 Fragment 中启动一个 Activity,然后从它启动的位置返回到上一个 Activity?
【发布时间】:2022-01-14 13:27:12
【问题描述】:

我一直在努力应对一个特殊的挑战,具体如下:

我的应用有一个活动“A”,它被视为应用的“主要”活动。在某个时刻,它启动了一个活动“B”,该活动有一个可用的操作,应该在活动“A”内启动一个片段(这并不总是同一个片段,它将取决于来自我们后端的一些数据)。

我可以通过简单地使用正确的 Intent 调用 startActivity 来做到这一点,但是,在按下后退按钮时,它会返回到 A 的“主要片段”(这是在 A 的 onBackButtonPressed() 内部实现的逻辑)。本质上,应该发生的事情如下:

Activity A -> Activity B -> Activity A 显示 Fragment X -> 按下返回 -> Activity B

使用startActivity 启动 Activity A 时会发生什么:

Activity A -> Activity B -> Activity A 显示 Fragment X -> 按回 -> Activity A 显示“主片段”。从这里,如果我再次按下应用程序退出,这又是 A 的 onBackButtonPressed 实现的一部分,但是我尝试从调用 A 的意图中检索 extra 以便有条件地恢复活动 B 但是由于我无法弄清楚的原因,意图似乎没有额外的东西。我确信我正确地将附加内容放入 Intent 中,因为活动 A 在根据我放在那里的内容从 B 调用时会启动正确的片段。

我尝试过的更多方法:

  • 直接从 B 中启动所需的片段,但是这样片段不会与存在于 A 中的导航栏一起显示,并且似乎在片段元素后面显示活动 B 的主要内容,这在用户体验方面是不可取的.

  • 使用Intent.FLAG_ACTIVITY_REORDER_TO_FRONT 标志,这似乎没有任何区别。

由于这是我公司的应用程序的一部分,它已经具有相当程度的复杂性,我不能随意为您提供有用的代码示例,希望我的描述足以帮助我。

其他信息

targetApi="n"
在 Android 11 上进行测试
活动 A 具有启动模式“singleTask”
Activity B 有launchMode "singleTop"

【问题讨论】:

  • 片段可以在活动中。活动不能在片段中。因此,您对预期和实际行为的描述很难理解,因为您一直在描述“在片段内”的 Activity A。
  • 您可以使用接口在活动 A 和 A 的片段之间进行通信。然后在活动 A 中,您可以使用接口将从意图检索到的额外数据发送到 A 的任何片段。然后在 A 的片段中,您可以在 onBackButtonPressed() 中使用 if 语句来返回 A 的主要片段或开始 B 活动。
  • 无论如何,我认为您的问题是 Activity A 的启动模式。它不能像您描述的那样有两种不同的启动模式,但是这两种模式中的任何一种都可以确保您一次只能有一个 Activity A时间不是您所描述的您想要的行为。
  • @Tenfour04 抱歉,我的措辞很糟糕,我知道片段是活动的一部分,而不是相反。我的意思是“显示片段 X 的活动 A”。我在描述启动模式时也犯了一个错误,我将编辑我的问题以反映这两个问题。

标签: android kotlin android-fragments android-activity


【解决方案1】:

对于预期的行为:

  1. 避免使用任何launchModetaskAffinity 或活动标志,默认行为绝对适合您的要求("standard" 是默认启动模式)。所以当你在 Activity B 中做这个动作时,将 B 放入 backstack 后会启动一个新的 Activity A 实例,这是默认行为。

  2. 你应该在 Activity A 的onBackPressed() 中有这样的逻辑:如果片段 X 是可见的,那么它将退出整个 Activity,否则它通过调用 super() 传递。类似于以下内容:

在活动 A 中

@Override
public void onBackPressed() {
    Fragment fragment = getFragmentManager().findFragmentByTag("yourTagForFragmentX");
    if (fragment instanceof XFragment) {
        // The fragment is available in the fragment manager
        finish()
    } else {
        super.onBackPressed();
    }
}

更多详情,here

【讨论】:

  • 感谢您的回答,这似乎为我指明了正确的方向,但是我担心在 Activity A 上调用 finish(),因为正如我所说,它是应用程序的主要支柱(绝大多数应用程序的功能都发生在其中,在特定条件下会弹出一些小活动),我担心破坏它的影响。有没有办法在没有finish() 调用的情况下实现这种行为?
  • 你明白没有singleTask启动模式,你的任务栈中会有多个ActivityA的实例吗?如果您 finish() 第二个托管 FragmentX,它将对您任务根目录下的 ActivityA 实例完全没有影响。
  • @Tenfour04 我确实不明白这一点,我很欣赏这个非常有用的解释。我想从它的名字就可以看出。我最终根据这个答案和下面的 dominicoder 成功解决了我的问题。主要的帮助是删除了“singleTask”启动模式,这让我可以更好地在活动之间切换。经过几个小时的调整业务逻辑和特定于应用程序的行为,我终于有了我想要的行为。谢谢大家的帮助!
【解决方案2】:

我认为你把事情复杂化了。

  1. 删除 A 和 B 的所有启动模式标志 - 它们不是必需的。
  2. 删除onBackPressed 的自定义处理 - 默认处理就足够了。
  3. 更新 A 以根据给出的意图将其自身初始化为正确的片段:

例如:

onCreate(...) {
    if (getIntent().getAction() == "START_ON_X") {
        // Notice we REPLACE and DO NOT add to back stack
        getFragmentManager().replace(fragID, createXFragment()).commit()
    }
    else {
        getFragmentManager().replace(fragID, createDefaultFragment()).commit()
    }
}

因此,您将拥有:

  1. 默认启动器意图启动 A.
  2. A 启动 B。
  3. B 启动 A 以显示片段 X 的特定意图

这会给你一堆 A -> B -> Ax

然后当你按下返回时,默认行为会让你留在 B 上。

然后再次按下返回将使您留在 A 上。

然后再次按返回将关闭您的应用程序。

这也是所有标准的默认行为。亲吻。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-07
    • 2014-05-15
    相关资源
    最近更新 更多