https://kotlinlang.org logo
#coroutines
Title
# coroutines
e

efemoney

08/14/2021, 10:55 AM
If I want to expose a “refreshable” flow as an input to my library, such that in addition to getting a stream of data, I as the library can also request for the latest data (as opposed to the latest cached data in the case of
StateFlow
) … will this be a good way?
Copy code
interface RefreshableFlow: Flow (or SharedFlow or StateFlow) {
  fun refresh()
}


class RefreshableFlowImpl(val delegate: flow): Flow by flow, RefreshableFlow {
  override fun refresh() { ... } // launch coroutine/send event/etc that would eventually or not emit a new value
}
What are the pitfalls of doing something like this?
e

Erik

08/14/2021, 1:15 PM
I would just expose a StateFlow, from which the reader can collect (stream) or just read the latest value. Additionally, expose a refresh function that triggers the refresh mechanism, which will emit the latest value through the same state flow. Optionally, if you want that, you can make the refresh function also return that latest value. You will likely want to make the refresh function suspending too in that case.
e

efemoney

08/14/2021, 1:20 PM
The type in question is an input to my library. Consumers will provide a stream of data (via Flow and subtypes) and I, the library, will subscribe to this flow and also tell the consumer when to refresh/requery the data flow (in addition to whenever they think they should refresh/requery the flow) I’m just trying to see how to combine that under a single type and if the approach above makes sense.
e

Erik

08/14/2021, 1:22 PM
You can just make an interface with that state flow as a val and the refresh function. Your consumers will provide an instance of that interface to your lib
The contract is that consumers will have to implement the interface and that the refresh function behaves like you described
No need to complicate things by making a new flow subtype
(composition over inheritance)
e

efemoney

08/14/2021, 1:32 PM
Thanks @Erik. I could (and I have that currently) but now I need to know if the approach of subclassing also makes sense. Am I breaking any coroutine (concurrency, dispatching etc) rules? Will this work with all current flow operators? etc Also I don’t agree in this case that
interface X { val flow: Flow ; fun refresh() }
is (necessarily) a better API. For one at the callsite, it becomes
x.flow.collect { ... }
vs
x.collect { ... }
which may be less desirable depending on the concept
x
is meant to represent. Also for the same reason why (I imagine)
StateFlow
is not defined as
interface StateFlow<T> { val flow: Flow ; val value: T}
what I want is a “flow that can be refreshed” and not an “entitity that has a flow and can be refreshed”
e

Erik

08/14/2021, 1:34 PM
Take a look at the Flow, SharedFlow and StateFlow KDoc: are these interfaces stable for inheritance? If so, then go ahead with your approach. Otherwise use composition.
6 Views