-
Notifications
You must be signed in to change notification settings - Fork 1.9k
StateFlow implementation #1974
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
StateFlow implementation #1974
Conversation
kotlinx-coroutines-core/common/src/flow/operators/StateFlowFusion.kt
Outdated
Show resolved
Hide resolved
Note, that it also fixes #395 and it removes the need for |
StateFlow is a Flow analogue to ConflatedBroadcastChannel. Since Flow API is simpler than channels APIs, the implementation of StateFlow is simpler. It consumes and allocates less memory, while still providing full deadlock-freedom (even though it is not lock-free internally). Fixes #1973 Fixes #395 Fixes #1816
* Move StateInTest * Add `out T` projection to StateFlow type
Co-authored-by: Vsevolod Tolstopyatov <[email protected]>
Also fixes #1816 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great!
@elizarov It makes sense when a sequence of actions needs to emit the same result through the StateFlow, or simply when retrying an action from a user interface has the same result. |
@proto-mvp Adding a timestamp or index to your data class can do. Otherwise, |
@LouisCAD I did something to make my data classes unique, but wanted to know if we could override it. |
If you have something like |
@proto-mvp What's your actual use-case? What kind of data are you sending? |
emitting states of UI on an MVI - reactive architecture. Ended up having an extra Id field to distinguish and get the behaviour I wanted with StateFlow. I know it is by design distinctUntilChanged enabled, but would be handy to have a StateFlow without this behaviour, in cases we need to drop MutableLiveData, or PublishSubject from Rx.Java, and not having to use channels. |
that is a good tip. Changing the sequence of the values should work. Will give it a go. Cheers! |
This is what |
Great question @proto-mvp. I experienced the same use case this week when building a Model-View-Intent (MVI) pattern proof-of-concept with StateFlow. The proposed solution of 'having an extra ID field to distinguish unique data' will work. Another solution, if no extra data is required for the intent, is using a new class or data class instance, when data is needed. Either can be set to the In the sample below every time Emit.kt class Emit SomeFragment.kt @ExperimentalCoroutinesApi
class FeedFragment : Fragment(), SomeView {
private var loadRequestIntent = MutableStateFlow<Emit?>(null)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if (savedInstanceState == null)
loadRequestIntent.value = Emit()
}
override fun loadNetworkIntent() = loadRequestIntent.filterNotNull()
} SomeView.kt interface SomeView {
/**
* Load feed from the network
*
* @return A flow emitting the feed state returned from the network
*/
@ExperimentalCoroutinesApi
fun loadNetworkIntent(): Flow<Emit>
} SomeViewModel.kt @ExperimentalCoroutinesApi
class FeedViewModel(private val repository: FeedRepository) : ViewModel() {
fun bindIntents(view: FeedView) {
view.loadNetworkIntent().onEach {
loadNetwork(it.toRetry)
}.launchIn(viewModelScope)
} |
@AdamSHurwitz
Who's going to trigger a data reload after process death then? 🤔 |
This is a great point @Zhuinden. In the sample above, when a process death occurs The result in the sample code is there will not be a new network request for data, however existing data persisted in Room database will populate the view state. In the full ViewModel implementation the above sample is derived from, if a new network data request is not made from I need to think more in-depth about a clean way to refresh the network request on process death vs. relying on a manual swipe-to-refresh to this point. I'm open to suggestions as well! 🙏🏻 Also, I'm updating the open-source Coinverse app with a full sample of the above pattern I will share with you @Zhuinden once drafted. |
@Zhuinden, here is the full Coinverse sample using StateFlow with a Model-View-Intent pattern. Re: "Who's going to trigger a data reload after process death then?" Thinking more about your WorkManager (WM) suggestion over DMs. An implementation could look like WM checking a SharedPref value to see when the network data was last updated, and emit |
StateFlow is a Flow analogue to ConflatedBroadcastChannel. Since Flow API is simpler than channels APIs, the implementation of StateFlow is simpler. It consumes and allocates less memory, while still providing full deadlock-freedom (even though it is not lock-free internally). Fixes Kotlin#1973 Fixes Kotlin#395 Fixes Kotlin#1816 Co-authored-by: Vsevolod Tolstopyatov <[email protected]>
StateFlow is a Flow analogue to ConflatedBroadcastChannel. Since Flow API is simpler than channels APIs, the implementation of StateFlow is simpler. It consumes and allocates less memory, while still providing full deadlock-freedom (even though it is not lock-free internally).
Fixes #1973 (see the issue for design and discussion)