android 管理fragment,在 Fragment 之间传递数据

从 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...

}

});

}

73cd31e26da3256b897e03188d57c687.png

图 1. Fragment B 使用 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 为 DESTROYED 后,您就无法再对该 Fragment 设置监听器。

在父级 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..

}

});

}

3538e56f469cd7968d7e8fa48b557fe6.png

图 2. 子级 Fragment 可以使用 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()

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()

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))

}

}

}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值