Skip to content

Instantly share code, notes, and snippets.

@marcellogalhardo
Last active July 23, 2023 23:46
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marcellogalhardo/2a1ec56b7d00ba9af1ec9fd3583d53dc to your computer and use it in GitHub Desktop.
Save marcellogalhardo/2a1ec56b7d00ba9af1ec9fd3583d53dc to your computer and use it in GitHub Desktop.
A helper function to let you expose a MutableStateFlow from a SavedStateHandle.
/**
* Returns a [StateFlow] that access data associated with the given key.
*
* @param scope The scope used to synchronize the [StateFlow] and [SavedStateHandle]
* @param key The identifier for the value
* @param initialValue If no value exists with the given [key], a new one is created
* with the given [initialValue].
*
* @see SavedStateHandle.getLiveData
*/
fun <T> SavedStateHandle.getStateFlow(
scope: CoroutineScope,
key: String,
initialValue: T
): MutableStateFlow<T> {
val liveData = getLiveData(key, initialValue)
val stateFlow = MutableStateFlow(initialValue)
// Synchronize the LiveData with the StateFlow
val observer = Observer<T> { value ->
if (stateFlow.value != value) {
stateFlow.value = value
}
}
liveData.observeForever(observer)
stateFlow.onCompletion {
// Stop observing the LiveData if the StateFlow completes
withContext(Dispatchers.Main.immediate) {
liveData.removeObserver(observer)
}
}.onEach { value ->
// Synchronize the StateFlow with the LiveData
withContext(Dispatchers.Main.immediate) {
if (liveData.value != value) {
liveData.value = value
}
}
}.launchIn(scope)
return stateFlow
}
@StylianosGakis
Copy link

As per the documentation inside kotlinx.coroutines.flow.MutableStateFlow.value:
"Setting a value that is [equal][Any.equals] to the previous one does nothing."
Doesn't that mean that this is redundant?

if (stateFlow.value != value) {
    stateFlow.value = value
}

and can be replaced with:

stateFlow.value = value

And with that said, are you aware if any library maintains this function? It's kind of hard to share and have people to use this as a gist.

@marcellogalhardo
Copy link
Author

marcellogalhardo commented Nov 23, 2021

Hey @StylianosGakis.

Yes, based in the documentation you posted you can remove the if-else.

About a library, I'm not familiar with any but I guess it is simpler to write a custom function in each project for that - I expect Google to add flow support to SavedStateHandle at some point in the future.

@PatrickKuijpers
Copy link

Great helper function, thanks!

Would it be an idea to make T : Parcelable?

@marcellogalhardo
Copy link
Author

marcellogalhardo commented Jul 23, 2023

Hey @PatrickKuijpers, that would work but keep in mind you would block those functions to be used with primitives and other supported types (such as lists), I think. That isn't a problem per see, so go ahead if these are the only types you need in your project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment