明确关于 onActivityResult 管理与活动和片段的主题

Clear topic about onActivityResult management with activities and fragments

我正在写这个 Whosebug 问题,因为我还没有阅读关于 Android onActivityResult 在涉及片段和活动时的功能的明确问题解决方案。我想拥有的(即使我很确定我不会有太多参与)将在这里有一些元素来理解每种情况下 onActivityResult 的情况,因为其中一些看起来很随机。

根据我在 SO 上看到的问题,有一个经典案例(startActivityForResultonActivityResult 在同一个 activity 上)和 3 confusing/not工作案例:

我的第一个问题是:Android API 是否为这些用例做好了准备? 然后主要问题是:它是如何工作的?因为即使有 Google 参考,我所看到的唯一用例也是经典案例。从我读到的关于它的其他问题来看,其他情况对我来说似乎不清楚。

希望能帮到你。尽管缺少文档,您可以浏览源代码并检查它们是如何工作的。我能观察到但我可能错了的是:

从Activity开始

Activity.startActivityForResult(requestCode) --- > Activity.onActivityResult(requestCode)

从片段开始

Fragment.startActivityForResult(requestCode) -> Activity.startActivityForResult(maskedRequestCode) -> |
                                                                                                      |
                                                                                                      |
  Fragment.startActivityForResult(requestCode) <--  Activity.onActivityResult(maskedRequestCode)  < - |

如您所见,当您调用 Fragment.startActivityForResult 时,该片段将从主机 Activity 调用类似的方法。但是,主机 Activity 将屏蔽 requestCode 以了解哪个片段触发了该操作。 这样,在 onActivityResult 期间,Activity 将取消屏蔽该值,以便将结果传递给适当的片段(因为 activity 可能托管多个片段等)。

因此,基于此,您应该启动一个 activity 并在同一元素上处理其结果。否则,您将无法正确确定 requestCode。因为如果 Fragment 启动了 activity,托管 activity 将只能访问屏蔽值(无需复制代码来取消屏蔽值,您无法确定 requestCode 采取适当的行动)。

请记住,您可以通过片段与 activity 进行通信:

class MainActivity {
    public void startActivityX() {
        startActivityForResult(ACTIVITY_X_REQUEST_CODE);
    }
}

class MainFragment {
    public void startActivityX() {
        ((MainActivity)getActivity()).startActivityX();
    }
}

反向也有效。您可以获得 Fragment 的实例,转换为 MainFragment 并调用您需要的方法。

基本上,你应该:

  • 如果 start/result 由 Activity 处理,则通过 Activity

  • 启动并处理
  • 如果 start/restult 将由 Fragment 处理,则开始启动并通过 Fragment

  • 处理
  • 如果FragmentActivity共享start/result,则通过Activity启动并处理它。然后,activity 回调 Fragment 上的方法。在你的 Fragment 中,你可以通过 getActivity() 获得 Activity。此外,在 Activity 上,您可以通过 getFragmentByTag() 获取 Fragment 的引用 因此,可以从另一个元素调用一个元素的方法,反之亦然。

我也分享了 requestCode 是如何被屏蔽的等等。它可能对你有帮助。

W0rmH0le 的回答很好,我同意他写的。但是,我想阐明为什么人们认为 Fragment.startActivityForResult() 已损坏。

如果调用 super.onActivityResult() 失败,

onActivityResult() 不会 抛出异常。但是,如果您在 Activity 中覆盖此方法并希望能够在片段中处理结果,则 必须调用 super

super.onActivityResult() 是揭露 requestCode 并将结果分派给 Fragment 的机制。所以,如果你的 Activity 有这样的代码:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == foo) {
        // do something
    }
}

这会破坏你的碎片。添加 super 调用:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == foo) {
        // do something
    }
}

现在屏蔽的 requestCode 将被正确处理,结果将按预期发送到您的 Fragment。