[Flow] combineTransformLatest()
See original GitHub issueI’d like to propose introduce new combineTransformLatest
operator , which behaves like combineTransform
but cancels transformer if new value arrives.
Example: loading places to map; user is moving with map, which cancels the previous fetching, also the loaded data depend on filter or other Flows.
I've implement this
class Symbol(val symbol: String) {
override fun toString(): String = symbol
@Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE")
inline fun <T> unbox(value: Any?): T = if (value === this) null as T else value as T
}
val NULL = Symbol("NULL")
inline fun <reified T, R> combineTransformLatest(
vararg flows: Flow<T>,
@BuilderInference crossinline transform: suspend FlowCollector<R>.(Array<T>) -> Unit
): Flow<R> {
return channelFlow {
coroutineScope {
val size = flows.size
val channels = flows.map { flow ->
this@coroutineScope.produce<Any> {
flow.collect { value ->
this@produce.send(value ?: NULL)
}
}
}
var job: Job? = null
val latestValues = arrayOfNulls<Any?>(size)
val isClosed = Array(size) { false }
while (!isClosed.all { it }) {
select<Unit> {
for (i in 0 until size) {
if (isClosed[i]) continue
@Suppress("DEPRECATION")
channels[i].onReceiveOrNull { receivedValue ->
if (receivedValue == null) {
isClosed[i] = true
} else {
latestValues[i] = receivedValue
if (latestValues.all { it !== null }) {
job?.apply {
cancel(CancellationException())
join()
}
job = launch {
val arguments = arrayOfNulls<T>(size)
for (index in 0 until size) {
arguments[index] = NULL.unbox(latestValues[index])
}
flow<R> {
@Suppress("UNCHECKED_CAST")
this@flow.transform(arguments as Array<T>)
}.collect {
this@channelFlow.send(it)
}
}
}
}
}
}
}
}
}
}
Not totally sure if the channelFlow as wrapper is correct, probably possible to do it without it but only with access to intenals.
I’m ok to have just this signature - varargs and with transformer, which allows not to emit or emit multiple times in opposite combineLatest().
Issue Analytics
- State:
- Created 4 years ago
- Reactions:10
- Comments:6 (5 by maintainers)
Top Results From Across the Web
combineTransform - Kotlin
Returns a Flow whose values are generated by transform function that process the most recently emitted values by each flow. The receiver of...
Read more >Koltin Flow flatMapLatest to combineTransform Using Multiple ...
Use Combine then flatMap latest on the top of that. private val _selectionLocation: MutableStateFlow<Location?> = MutableStateFlow(null) val ...
Read more >Combining Kotlin Flows with Select Expressions
How do we combine emissions from multiple Flows? We could use operators such as zip, flattenMerge and combine. This article will explore how...
Read more >How to Combine Kotlin Flows - Better Programming
Kotlin flow is one of the latest and most powerful features of Coroutines. In this article, we're going to learn how to combine...
Read more >Combining flows: merge, zip, and combine - Kt. Academy
suspend fun main() { val ints: Flow<Int> = flowOf(1, 2, 3) val doubles: Flow<Double> = flowOf(0.1, 0.2, 0.3) val together: Flow<Number> =...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
I managed to roll my own combineTransformLatest which is based on the existing operators 🎉
In fact,
combineTransform
should be called combineTransformConcat because any function that is suspended inside transform collector also suspend combines a bit like flatMapConcat operator.