New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Flow.last() operator #2246
Comments
Are you considered a StateFlow? |
@fvasco How state flow would help with it? I need the final value of flow, not the current value |
Interesting. Can you elaborate, please, on the kind of case where you ended up needing it? What kind of flow is that? |
Any kind of progress where the final item of flow is some result item The last case where I found it was a Flow which represents CI Job states, like I also had similar cases where I had a Flow which represents some file processing (we have a lot of them), it emits progress and the final item of this flow emits resulting processed file, so often consumer just wants to startFlow and receive final result |
Hi, @gildor, I am not suggesting you to use a |
@fvasco I'm really don't understand your suggestion. Yes, indeed I can use Deferred, but it works if I care only about the final result, but it's not the case, I still may need intermediate states to do some side effect: log, show progress, update status etc
Even this doesn't make sense for me, I don't see how deferred makes it better. Usually now instead of exposing one Flow for API, I introduce 2 method: 1 with flow with all intermediate states and 1 suspend function with the final result, it works fine for very often used apis, but sometimes I just want to receive the final result of existing Flow API |
Hi, @gildor,
Yes, indeed. I try to explain my concern, these are not strictly related to the In you example, you wrote: A first api specification can be A second proposal can be Instead, if a In any case, you defined a custom protocol ( suspend fun Flow<State>.await() = first { it.terminal } |
We got the same issue, we elaborate a sequence of event and have to get the last one. Unfortunately, we require a suspend fun inside a Here our patch: public suspend fun <T> Flow<T>.last(): T? = reduce { _, value -> value }
public suspend fun <T> Flow<T>.lastOrNull(): T? = fold<T?, T?>(null) { _, value -> value } |
I also have a case where having Here's a snippet for brevity: //[...]
fun getNextRuntimeUniqueInt(): Flow<Int?> {
return dataStore.data.mapLatest { prefs ->
prefs[Keys.NEXT_RUNTIME_UNIQUE_INT]
}
}
//[...]
val cnt = dataStoreHelper.getNextRuntimeUniqueLong().conflate().first() full context: DataStoreHelper.kt class DataStoreHelper(val context: Context) {
private val dataStore: DataStore<Preferences> = context.createDataStore(
name = "preferences"
)
fun getNextRuntimeUniqueInt(): Flow<Int?> {
return dataStore.data.mapLatest { prefs ->
prefs[Keys.NEXT_RUNTIME_UNIQUE_INT]
}
}
suspend fun setNextRuntimeUniqueInt(count: Int) {
dataStore.edit { prefs ->
prefs[Keys.NEXT_RUNTIME_UNIQUE_INT] = count
}
}
fun getNextRuntimeUniqueLong(): Flow<Long?> {
return dataStore.data.mapLatest { prefs ->
prefs[Keys.NEXT_RUNTIME_UNIQUE_LONG]
}
}
suspend fun setNextRuntimeUniqueLong(count: Long) {
dataStore.edit { prefs ->
prefs[Keys.NEXT_RUNTIME_UNIQUE_LONG] = count
}
}
} UniqueRuntimeNumberHelper.kt class UniqueRuntimeNumberHelper(val context: Context) {
companion object {
const val INITIAL_NEXT_INT = 1
const val INITIAL_NEXT_LONG = 1L
}
private val dataStoreHelper: DataStoreHelper = (context.applicationContext as App).kodein.instance()
/**
* Get a unique Integer, should only be used for runtime uniqueness
*/
suspend fun nextInt(): Int {
val cnt = dataStoreHelper.getNextRuntimeUniqueInt().conflate().first()
val intCounter = if (cnt != null) AtomicInteger(cnt) else AtomicInteger(INITIAL_NEXT_INT)
val value = intCounter.incrementAndGet()
return when {
(value < Int.MAX_VALUE) -> {
dataStoreHelper.setNextRuntimeUniqueInt(value)
value
}
else -> {
dataStoreHelper.setNextRuntimeUniqueInt(INITIAL_NEXT_INT)
INITIAL_NEXT_INT
}
}
}
/**
* Get a unique Long, should only be used for runtime uniqueness
*/
suspend fun nextLong(): Long {
val cnt = dataStoreHelper.getNextRuntimeUniqueLong().conflate().first()
val longCounter = if (cnt != null) AtomicLong(cnt) else AtomicLong(INITIAL_NEXT_LONG)
val value = longCounter.incrementAndGet()
return when {
(value < Long.MAX_VALUE) -> {
dataStoreHelper.setNextRuntimeUniqueLong(value)
value
}
else -> {
dataStoreHelper.setNextRuntimeUniqueLong(INITIAL_NEXT_LONG)
INITIAL_NEXT_LONG
}
}
}
} |
Hi @lmj0011, Similar to: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/last.html |
I found myself often doing this
flow.toList().last()
usually for code that works with Flow which represents progress, when I want to receive the final item, it would be complimentary to first()/single() itemIt also can be replaced with something like
but it's not always so simple, for example, a sealed hierarchy may have a few terminal types for operation
Reactive libraries have such operator http://reactivex.io/documentation/operators/last.html
The text was updated successfully, but these errors were encountered: