Following this question I made some simple changes in my app, but it's no working as I expect.
I have a Timer that sends a notification when the timer is done. Clicking this notification restarts the activity, deleting all the timer information, which is stored mainly in the viewModel
. For this reason, I decided to use saved State for viewModel
.
Here's my viewModel
:
class TimerViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
private val _secondsRemaining = savedStateHandle.getLiveData<Long>(SECONDS_REMAINING)
val secondsRemaining : LiveData<Long>
get() = _secondsRemaining
Here is how I use the viewModel
in my Fragment
:
private val timerViewModel by viewModels<TimerViewModel>()
When I start the timer, I save the value of the seconds remaining in the LiveData
, on every Tick of the clock. When the timer finishes, the app sends the notification and the timer starts again, counting a new cycle:
timer = object : CountDownTimer(timerLengthSeconds * 1000, 1000){
override fun onFinish(){
(....)
}
override fun onTick(millisUntilFinished: Long) {
var secondsRemainingInCountdown = millisUntilFinished / 1000
(...)
_secondsRemaining.value = secondsRemainingInCountdown
}
}.start()
}
So, when the timer finishes, the app sends the notification but the timer has restarted, and the seconds remaining are getting updated (I've checked this via Logs).
When the user clicks the notification the activity
gets killed and restarts, and the expactation would be to see the timer with the seconds remaining saved in the LiveData
. But when the activity
restarts, LiveData
value is null.
I have also tried setting a value of 10, in case LiveData
is null when first created
private val _secondsRemaining = savedStateHandle.getLiveData<Long>(SECONDS_REMAINING, 10)
but when the activity restarts, I get 10 as the value of LiveData
I can't figure out the reason.
My second problem is that I want to save the state of a LiveData
that stores a custom class
, that saves the state of the clock
private val _timerState = MutableLiveData<TimerState>()
val timerState : LiveData<TimerState>
get() = _timerState
Being this class
:
sealed class TimerState {
object OnFocusRunning : TimerState()
object OnRestRunning : TimerState()
object OnFocusPaused : TimerState()
object OnRestPaused : TimerState()
object Completed : TimerState()
object RestCompleted : TimerState()
object NotStarted : TimerState()
}
But I haven't succeed in this, since TimerState
is a custom class
and not a primitive type.
When you're using a
SavedStateHandle
you need to set your values on it to store them. If you usegetLiveData
for a particular key, then thatLiveData
will update whenever you set a new value for that key. If you're setting it directly on theLiveData
, you're bypassing the saved state:As for your other problem, yeah you're limited in what you can store, and for custom classes you either need to serialise them into a form you can store, or make them
Serializable
orParcelable
.In your case though, since that sealed class isn't doing anything special except being an instance of a type, I'd just make it an enum class instead - those are
Serializable
so you can throw the value straight in there!