3

We can create LiveData or StateFlow in a similar way as below

val _liveData = MutableLiveData(0)
val _stateFlow = MutableStateFlow(0)

But In LiveData, we can ensure the data is saved and restored by using

val _liveData: MutableLiveData<Int> = savedStateHandle.getLiveData("Key", 0)

For StateFlow, is there a way (or API) to keep the last value and restore it, like what we have in LiveData?

Elye
  • 53,639
  • 54
  • 212
  • 474

3 Answers3

3

I use the conventional way in ViewModel to store and restore the value

    private val _stateFlow = MutableStateFlow(
        savedStateHandle.get("key") ?: InitialValue
    )

And when setting the value

    _stateFlow.value = ChangeValue
    savedStateHandle.set("key", ChangeValue)

Not ideal, but at least we have a way to save the latest value.

And thanks to https://www.reddit.com/user/coffeemongrul/, who provided a proposal to wrap it around with a class as per https://www.reddit.com/r/androiddev/comments/rlxrsr/in_stateflow_how_can_we_save_and_restore_android/

class MutableSaveStateFlow<T>(
    private val savedStateHandle: SavedStateHandle,
    private val key: String,
    defaultValue: T
) {
    private val _state: MutableStateFlow<T> =
        MutableStateFlow(savedStateHandle.get<T>(key) ?: defaultValue)
    
    var value: T
        get() = _state.value
        set(value) {
            _state.value = value
            savedStateHandle.set(key, value)
        }

    fun asStateFlow(): StateFlow<T> = _state
}
Elye
  • 53,639
  • 54
  • 212
  • 474
0

Can you try this? I haven't tried it yet but I think it might work.

private val _stateFlow: MutableStateFlow<Int>?
    get()= savedStateHandle.get<MutableStateFlow<Int>>("KEY")
Hasan Kucuk
  • 2,433
  • 6
  • 19
  • 41
0

I can propose one more solution. A simple extension that will update SavedStateHandle once MutableStateFlow will be updated.

fun <T> SavedStateHandle.getMutableStateFlow(
    scope: CoroutineScope,
    key: String,
    initialValue: T
): MutableStateFlow<T> {
    return MutableStateFlow(get(key) ?: initialValue).apply {
        scope.launch(Dispatchers.Main.immediate) {
            this@apply.collect { value ->
                set(key, value)
            }
        }
    }
}
Andrey Liashuk
  • 240
  • 2
  • 5