android中的回调流

Convert any callback API into a self cleaning Flow.

将所有回调API转换为自清除流。

Kotlin Flows are amazing. Not only do they provide a non-blocking asynchronous way to deal with sequences of values, but they provide a clean and powerful API for dealing with event driven programming. Flows are easy to clean up to prevent leaks. They provide many functions and operators to deal with a myriad of scenarios and requirements. With an experimental function they are super easy to create around callback APIs.

Kotlin Flows很棒。 它们不仅提供了一种处理值序列的非阻塞异步方式,而且还提供了一种用于处理事件驱动程序的干净而强大的API。 流量易于清理以防止泄漏。 他们提供了许多功能和操作员来应对各种场景和要求。 通过实验功能,它们非常容易围绕回调API创建。

The Jetpack team added CoroutineScope support to the lifecycle in lifecycle-runtime-ktx version 2.2.0-alpha01. This allowed callers to launch coroutines in created, started, and resumed states that automatically cancelled them in the appropriate complementary state. For example the following Flow will be collected while the activity is started and stop when the onStop method is called:

Jetpack团队在lifecycle-runtime-ktx版本2.2.0-alpha01向生命周期添加了CoroutineScope支持。 这使调用者可以在创建,启动和恢复状态下启动协程,并在适当的互补状态下自动取消协程。 例如,将在活动开始时收集以下Flow并在onStop方法时停止以下Flow

lifecycleScope.launchWhenStarted {
viewModel.getFlow().collect {
// Do something with value
}
}

Additionally they added a viewModelScope in lifecycle-viewmodel-ktx version 2.1.0-beta01. This scope cancels coroutines when ViewModel.onCleared() is called. By properly using these scopes, we avoid having to remember to stop collecting from our flows, and avoid leaking long running processes when we no longer need them.

另外,他们在lifecycle-viewmodel-ktx版本2.1.0-beta01添加了viewModelScope 。 调用ViewModel.onCleared()时,此作用域取消协程。 通过正确使用这些作用域,我们不必记住必须停止从流中收集数据,并避免在不再需要长时间运行的流程时泄漏它们。

Many times when dealing with event based programming, developers want to be selective about what events they deal with. Kotlin Flows provide a great set of APIs to help simplify that process and avoid cluttering our collection code. Here are a few of my favorites:

很多时候,在处理基于事件的编程时,开发人员都希望对处理的事件保持选择性。 Kotlin Flows提供了很多API,可帮助简化该过程并避免使我们的收集代码混乱。 以下是一些我的最爱:

  • fitlerIsInstance — include values that are of a given type and cast them.

    fitlerIsInstance -包括那些给定类型铸造他们的值。

  • filterNotNull — include values that are not null

    filterNotNull —包含不为null的值

  • debounce — filter out values by the newer values within a given timeout. Limiting rate of values so we don’t have to process unimportant, superseded ones.

    debounce —在给定的超时时间内通过较新的值过滤掉值。 限制值的速率,因此我们不必处理不重要的,被取代的值。

  • mapLatest — transform the latest value by the provided transform function.

    mapLatest —通过提供的转换函数转换最新值。

  • flatMapLatest — like the map operator above but returns the values from the new flow returned by the transform function.

    flatMapLatest —与上面的地图运算符一样,但是从transform函数返回的新流中返回值。

  • combine — combine the most recently emitted values of multiple flows.

    combine -合并多个流的最新发出的值。

  • distinctUntilChanged — filter out subsequent repetition of values.

    distinctUntilChanged过滤出后续的值重复。

  • buffer — buffer value emission to handle back pressure.

    buffer —发出缓冲值以处理背压。

  • flowOn — change the context on which the preceding operations are executed.

    flowOn —更改在其上执行前面的操作的上下文。

In Android, there are many libraries and systems that we would love to get a flow of events or values that we can easily operate on in the background. Version 1.3.0-M1 of coroutines added a new experimental flow builder called callbackFlow. This builder provides a simple and easy way to create a flow for callback based APIs. The key piece is the function awaitClose which lets us remove/unregister our callbacks when the flow is closed.

在Android中,我们希望获得许多库和系统,以便获得可以在后台轻松进行操作的事件或值的流程。 协程的1.3.0-M1版本添加了一个新的实验流程构建器,称为callbackFlow 。 此构建器提供了一种简单的方法来为基于回调的API创建流。 关键是函数awaitClose ,它使我们可以在流程关闭时删除/注销回调。

A simple example is using a TextWatcher to perform a search while the user is typing. Now we don’t want to search while the user is frantically typing so we can combine the callbackFlow, buffer, and the debounce functions to make that simple:

一个简单的示例是在用户键入时使用TextWatcher进行搜索。 现在我们不想在用户疯狂输入时搜索,因此我们可以结合使用callbackFlowbufferdebounce函数来简化操作:

fun TextView.textWatcherFlow(): Flow<CharSequence?> = callbackFlow<CharSequence?> {
val textWatcher = object: TextWatcher {
override fun afterTextChanged(s: Editable?) {
sendBlocking(s)
}
// Other callback mehthods
}
addTextChangedListener(textWatcher)
awaitClose { removeTextChangedListener(textWatcher) }
}.buffer(Channel.CONFLATED)
.debounce(300L)

The first step inside the callbackFlow is to create ourTextWatcher. Inside that callback we use sendBlocking to pass the values we care about to the flow. Next we add the callback to the TextView followed immediately by awaitClose. Inside that block we remove the TextWatcher, so we are fully cleaning up our listener. Now, sendBlocking can block, as the name indicates, but by using buffer we can avoid that from happening. In this case we want to use CONFLATED to only send the latest value if there are conflicts. Lastly we use debounce to wait for a lull of 300 ms in the typing before emitting the last value. We will keep getting new values at a rate of 300 ms or slower until the scope we launched with collect in is cancelled.

callbackFlow内部的第一步是创建TextWatcher 。 在该回调内部,我们使用sendBlocking将我们关心的值传递给流。 接下来,我们将回调添加到TextView紧接着是awaitClose 。 在该块内,我们删除了TextWatcher ,因此我们正在完全清理侦听器。 现在, sendBlockingsendBlocking可以阻止,但是通过使用buffer我们可以避免这种情况的发生。 在这种情况下,我们希望使用CONFLATED仅在发生冲突时发送最新值。 最后,在发出最后一个值之前,我们使用debounce来等待300 ms的暂停。 在取消使用collect in启动的作用域之前,我们将以300毫秒或更慢的速度获取新值。

lifecycleScope.launchWhenStarted {
textView.textWatcherFlow().collect {
// pass value to viewModel to perform search
}
}

But wait, there’s more

但是等等,还有更多

What if we want to stop collecting mid scope? All of the launch functions: launch, launchWhenCreated, launchWhenStarted, launchWhenResumed return a coroutine Job. A job gives us a handle on the coroutine so we can cancel it when necessary as follows:

如果我们要停止收集中视镜怎么办? 所有启动功能: launchlaunchWhenCreatedlaunchWhenStartedlaunchWhenResumed返回协程Job 。 一项工作为我们提供了协程的处理,因此我们可以在必要时取消它,如下所示:

val job = lifecycleScope.launchWhenStarted {
textView.textWatcherFlow().collect {
// pass value to viewModel to perform search
}
}job.cancel()

Cancelling a Job will cancel the Flow and trigger the awaitClose block cleaning up our callback.

取消Job将取消Flow并触发awaitClose块以清理回调。

Flows are powerful and callbackFlow makes it super easy to turn any callback based API into a self cleaning flow.

流程功能强大, callbackFlow使将任何基于回调的API转换为自清洁流程变得非常容易。

翻译自: https://medium.com/swlh/callback-flows-in-android-d2c6ed5bc488

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值