Android片段片段结果

Passing data between Fragments can be achieved in various ways, including using the target Fragment APIs (Fragment.setTargetFragment() and Fragment.getTargetFragment()), ViewModel or the Fragments’ parent Activity. The target Fragment APIs have recently been deprecated, and the encouraged way to pass data between Fragments is now the Fragment result APIs, where passing the data is handled by a FragmentManager, and Fragments can be set up to receive and send data.

Fragment之间传递数据的方式有多种,包括使用目标Fragment API( Fragment.setTargetFragment()Fragment.getTargetFragment() ), ViewModelFragment的父Activity 。 目标Fragment API最近已被弃用,现在鼓励使用的在Fragment之间传递数据的方式是Fragment结果API,其中通过FragmentManager处理数据的传递,并且Fragment可以设置为接收和发送数据。

在片段之间传递数据 (Passing Data Between Fragments)

To pass data between 2 Fragments without them having references to each other, you can now use their common FragmentManager, which acts as a central store for data passed between Fragments.

要在两个Fragment之间传递数据而又彼此之间没有引用,您现在可以使用它们的公用FragmentManager ,它充当Fragment之间传递的数据的中央存储。

接收资料 (Receiving Data)

If a Fragment expects to receive data, it can register a FragmentResultListener on a FragmentManager and specify a key to identify the data it expects, this acts as a filter to the data the FragmentManager sends it.

如果一个Fragment预期接收数据时,它可以注册一个FragmentResultListener上的FragmentManager和指定一个密钥,以确定它期望数据,这作为一个过滤器的数据FragmentManager发送。

FragmentManager.setFragmentResultListener(
    requestKey,
    lifecycleOwner,
    FragmentResultListener { requestKey: String, result: Bundle ->
        // Handle result
    })

The lifecycleOwner argument allows for data to be received only if it’s at least in a STARTED state. If the LifecycleOwner is the Fragment itself, you can safely update the UI when new data is received, since the View will have been created by that point (onViewCreated() is called before onStart()).

lifecycleOwner参数仅在数据至少处于STARTED状态时才允许接收数据。 如果LifecycleOwnerFragment本身,你可以当接收新的数据安全地更新UI,因为View将是由点创建( onViewCreated()被调用之前onStart()

Image for post
A result is received if the Fragment’s lifecycle is at least in the started state
如果片段的生命周期至少处于启动状态,则收到结果

If multiple data is passed to the Fragment before it reaches the STARTED state, it’ll only receive the latest value if it eventually reaches the STARTED state.

如果有多个数据传递给Fragment到达之前STARTED状态,它只会收到最新的值,如果它最终到达STARTED状态。

Image for post
The latest result is received when the Fragment’s lifecycle reaches the started state
当片段的生命周期达到启动状态时,将收到最新结果

When the LifecycleOwner reaches the DESTROYED state, it automatically unregisters the listener. To manually unregister it beforehand, call FragmentManager.setFragmentResultListener() again with the same request key, only this time pass in a null FragmentResultListener.

LifecycleOwner达到DESTROYED状态时,它将自动注销注册侦听器。 要预先手动注销,请使用相同的请求密钥再次调用FragmentManager.setFragmentResultListener() ,仅这次传入null FragmentResultListener

Image for post
A result is not passed after the Fragment’s lifecycle reaches the destroyed state
片段的生命周期达到销毁状态后,结果不会通过

The FragmentManager used to register the listener depends on the Fragments that can send back data.

FragmentManager用于注册监听器依赖于Fragment s表示可以发送回数据。

  • If FragmentA expects to receive data from FragmentB and both are on the same level, they can both communicate through their parent FragmentManager, and FragmentA must register its listener using its parent FragmentManager.

    如果FragmentA希望从FragmentB接收数据并且两者都处于同一级别,则它们都可以通过其父FragmentManager通信,并且FragmentA必须使用其父FragmentManager注册其侦听器。

parentFragmentManager.setFragmentResultListener(...)
  • If FragmentA expects to receive data from FragmentB and FragmentA is FragmentB’s parent, they can both communicate through FragmentA’s child FragmentManager, which is FragmentB’s parent FragmentManager.

    如果FragmentA希望从FragmentB接收数据,并且FragmentAFragmentB的父级,则它们都可以通过FragmentA的子FragmentManager通信,后者是FragmentB的父级FragmentManager

childFragmentManager.setFragmentResultListener(...)

Essentially, the listener must be set on a common FragmentManager.

本质上,侦听器必须在公共 FragmentManager上设置。

传送资料 (Sending Data)

If FragmentB needs to send data to FragmentA, it can pass it through a common FragmentManager (the parent FragmentManager) using the request key FragmentA registered its listener with.

如果FragmentB需要将数据发送到FragmentA ,它可以使用注册了其侦听器的请求键FragmentA将其通过通用FragmentManager (父FragmentManager )传递。

parentFragmentManager.setFragmentResult(
    requestKey, // Same request key FragmentA used to register its listener
    bundleOf(key to value) // The data to be passed to FragmentA
)

测试片段结果 (Testing Fragment Results)

To test that a Fragment receives or sends data successfully, you can use the FragmentScenario API, which provides the benefit of testing your Fragment in isolation.

要测试Fragment是否成功接收或发送数据,可以使用FragmentScenario API,它提供了隔离测试Fragment的好处。

接收资料 (Receiving Data)

If FragmentA registers a FragmentResultListener to receive data, you can simulate the action of sending this data using the Fragment’s parent FragmentManager. If FragmentA’s listener is set up correctly, it should receive the data, verify this by either retrieving it from FragmentA, or verifying a side effect of the reception, for example, if FragmentA displays data it receives on the UI, verify the expected data is displayed using Espresso APIs.

如果FragmentA注册一个FragmentResultListener来接收数据,则可以使用Fragment的父FragmentManager来模拟发送此数据的操作。 如果FragmentA的侦听器设置正确,它应该接收数据,或者通过从FragmentA检索它来验证数据,或者验证接收的副作用,例如,如果FragmentA在UI上显示它接收到的数据,请验证预期的数据使用Espresso API显示。

@Test
fun shouldReceiveData() {
    val scenario = FragmentScenario.launchInContainer(FragmentA::class.java)


    // Pass data using the parent fragment manager
    scenario.onFragment { fragment ->
        val data = bundleOf(KEY_DATA to "value")
        fragment.parentFragmentManager.setFragmentResult("aKey", data)
    }


    // Verify data is received, for example, by verifying it's been displayed on the UI
   onView(withId(R.id.textView)).check(matches(withText("value"))) 
}

传送资料 (Sending Data)

You can test whether FragmentB correctly sends data by setting up a FragmentResultListener on its parent FragmentManager inside the test, sending the result, then verifying the listener successfully received the data.

您可以测试是否FragmentB正确通过设置数据发送FragmentResultListener其父FragmentManager测试中,将结果发送,然后验证成功接收数据的监听器。

@Test
fun shouldSendData() {
    val scenario = FragmentScenario.launchInContainer(FragmentB::class.java)


    // Register result listener
    var receivedData = ""
    scenario.onFragment { fragment ->
        fragment.parentFragmentManager.setFragmentResultListener(
            KEY,
            fragment,
            FragmentResultListener { key, result ->
                receivedData = result.getString(KEY_DATA)
            })
    }


    // Send data
    onView(withId(R.id.send_data)).perform(click())


    // Verify data was successfully sent
    assertThat(receivedData).isEqualTo("value")
}

样例项目 (Sample Project)

Below is a sample project that demonstrates using the Fragment Result APIs.

下面是一个示例项目,演示了如何使用Fragment Result API。

结论 (Conclusion)

While the deprecation of the Fragment target APIs and their replacement with the Fragment result APIs is a bit limiting since the latter only allows for Bundles to be passed, thus only simple type, Serializable and Parcelable data can be passed, the Fragment result APIs allow to properly recover from process death and to pass data between Fragments without the need to hold references to each other, which prevents issues that may occur from accessing a Fragment in an unpredictable state.

尽管Fragment目标API的弃用和用Fragment结果API的替换是一个位限制,因为后者仅允许传递Bundle ,因此只能传递简单类型,可Serializable和可Parcelable数据,但Fragment结果API允许可以从进程终止中正确恢复并在Fragment之间传递数据,而无需彼此之间保持引用,这可以防止在无法预测的状态下访问Fragment可能发生的问题。

Want more Fragments goodness? Check out:

是否需要更多Fragment的优点? 退房:

For more on Java, Kotlin and Android, follow me to get notified when I write new posts or let’s connect on Github and Twitter!

有关Java,Kotlin和Android的更多信息,请在我撰写新帖子或关注GithubTwitter关注我,以得到通知!

翻译自: https://proandroiddev.com/android-fragments-fragment-result-805a6b2522ea

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值