从 Fragment 1.3.0-alpha04
开始,每个 FragmentManager
都会实现 FragmentResultOwner
。这意味着 FragmentManager
可以充当 Fragment 结果的集中存储区。此更改通过设置 Fragment 结果并监听这些结果,而不要求 Fragment 直接引用彼此,让单独的 Fragment 相互通信。
如需将数据从 Fragment B 传回到 Fragment A,请先在接收结果的 Fragment A 上设置结果监听器。在 Fragment A 的 FragmentManager
上调用 setFragmentResultListener()
API,如以下示例所示:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Use the Kotlin extension in the fragment-ktx artifact setResultListener("requestKey") { key, bundle -> // We use a String here, but any type that can be put in a Bundle is supported val result = bundle.getString("bundleKey") // Do something with the result... } }
Java
@Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); getParentFragmentManager().setFragmentResultListener("key", this, new FragmentResultListener() { @Override public void onFragmentResult(@NonNull String key, @NonNull Bundle bundle) { // We use a String here, but any type that can be put in a Bundle is supported String result = bundle.getString("bundleKey"); // Do something with the result... } }); }

FragmentManager
将数据发送到 Fragment A。在生成结果的 Fragment B 中,您必须使用相同的 requestKey
在同一 FragmentManager
上设置结果。您可以使用 setFragmentResult()
API 来完成此操作:
Kotlin
button.setOnClickListener { val result = "result" // Use the Kotlin extension in the fragment-ktx artifact setResult("requestKey", bundleOf("bundleKey" to result)) }
Java
button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Bundle result = new Bundle(); result.putString("bundleKey", "result"); getParentFragmentManager().setFragmentResult("requestKey", result); } });
然后,在值为 STARTED
后,Fragment A 便会收到结果并执行监听器回调。
对于一个指定键,您只能有一个监听器和一个结果。如果您对同一个键多次调用 setResult()
,则系统会将 Fragment B 从返回堆栈退出之前的最近结果发送给 Fragment A。如果您设置的结果没有相应的监听器来接收,则结果会存储在 FragmentManager
中,直到您设置一个具有相同键的监听器。请注意,监听器的 Fragment 必须为 STARTED
,然后该 Fragment 才能收到结果。监听器收到结果并触发 onFragmentResult()
回调后,结果会被清除。这种行为有两个主要影响:
- 返回堆栈上的 Fragment 只有在被弹出栈顶且为
STARTED
之后才会收到结果。 - 如果在设置结果时监听结果的 Fragment 为
STARTED
,则系统会立即触发监听器的回调。
在父级 Fragment 和子级 Fragment 之间传递结果
如需将结果从子级 Fragment 传递到父级 Fragment,父级 Fragment 在调用 setFragmentResultListener()
时应使用 getChildFragmentManager()
而不是 getParentFragmentManager()
。
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // We set the listener on the child fragmentManager childFragmentManager.setResultListener("requestKey") { key, bundle -> val result = bundle.getString("bundleKey") // Do something with the result.. } }
Java
@Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // We set the listener on the child fragmentManager getChildFragmentManager().setFragmentResultListener("key", this, new FragmentResultListener() { @Override public void onFragmentResult(@NonNull String key, @NonNull Bundle bundle) { String result = bundle.getString("bundleKey"); // Do something with the result.. } }); }

FragmentManager
将结果发送到其父级 Fragment。子级 Fragment 在其 FragmentManager
上设置结果。然后,当父级 Fragment 为 STARTED
时便会收到结果:
Kotlin
button.setOnClickListener { val result = "result" // Use the Kotlin extension in the fragment-ktx artifact setResult("requestKey", bundleOf("bundleKey" to result)) }
Java
button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Bundle result = new Bundle(); result.putString("bundleKey", "result"); // The child fragment needs to still set the result on its parent fragment manager getParentFragmentManager().setFragmentResult("requestKey", result); } });
测试 Fragment 结果
使用 FragmentScenario
测试对 setFragmentResult()
和 setFragmentResultListener()
的调用。使用 launchFragmentInContainer
或 launchFragment
为被测 Fragment 创建场景,然后手动调用目前未测试的方法。
如需测试 setResultListener()
,请使用调用 setResultListener()
的 Fragment 创建一个场景。接下来,直接调用 setResult()
并验证结果:
@Test
fun testFragmentResultListener() {
val scenario = launchFragmentInContainer<ResultListenerFragment>()
scenario.onFragment { fragment ->
val expectedResult = "result"
fragment.parentFragmentManagager.setResult("requestKey", bundleOf("bundleKey" to expectedResult))
assertThat(fragment.result).isEqualTo(expectedResult)
}
}
class ResultListenerFragment : Fragment() {
var result : String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Use the Kotlin extension in the fragment-ktx artifact
setResultListener("requestKey") { key, bundle ->
result = bundle.getString("bundleKey")
}
}
}
如需测试 setResult()
,请使用调用 setResult()
的 Fragment 创建一个场景。接下来,直接调用 setResultListener()
并验证结果:
@Test
fun testFragmentResult() {
val scenario = launchFragmentInContainer<ResultFragment>()
lateinit var actualResult: String?
scenario.onFragment { fragment ->
fragment.parentFragmentManagager.setResultListener("requestKey") { key, bundle ->
actualResult = bundle.getString("bundleKey")
}
}
onView(withId(R.id.result_button)).perform(click())
assertThat(actualResult).isEqualTo("result")
}
class ResultFragment : Fragment(R.layout.fragment_result) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
view.findViewById(R.id.result_button).setOnClickListener {
val result = "result"
// Use the Kotlin extension in the fragment-ktx artifact
setResult("requestKey", bundleOf("bundleKey" to result))
}
}
}