savedStateHandle 不保存状态
savedStateHandle not saving State
根据 this 问题,我对我的应用程序做了一些简单的更改,但它没有像我预期的那样工作。
我有一个计时器,它会在计时器结束时发送通知。单击此通知会重新启动activity,删除所有定时器信息,主要存储在viewModel
中。出于这个原因,我决定使用 viewModel
.
的保存状态
这是我的 viewModel
:
class TimerViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
private val _secondsRemaining = savedStateHandle.getLiveData<Long>(SECONDS_REMAINING)
val secondsRemaining : LiveData<Long>
get() = _secondsRemaining
这是我在 Fragment
中使用 viewModel
的方法:
private val timerViewModel by viewModels<TimerViewModel>()
当我启动计时器时,我会在时钟的每个滴答声中将剩余的秒数保存在 LiveData
中。当计时器结束时,应用程序发送通知,计时器再次启动,计算一个新的周期:
timer = object : CountDownTimer(timerLengthSeconds * 1000, 1000){
override fun onFinish(){
(....)
}
override fun onTick(millisUntilFinished: Long) {
var secondsRemainingInCountdown = millisUntilFinished / 1000
(...)
_secondsRemaining.value = secondsRemainingInCountdown
}
}.start()
}
因此,当计时器结束时,应用程序会发送通知,但计时器已重新启动,剩余的秒数正在更新(我已通过日志检查过)。
当用户单击通知时,activity
被终止并重新启动,并且解释是查看计时器,剩余秒数保存在 LiveData
中。但是当 activity
重新启动时, LiveData
值为空。
我也尝试过将值设置为 10,以防 LiveData
在首次创建时为 null
private val _secondsRemaining = savedStateHandle.getLiveData<Long>(SECONDS_REMAINING, 10)
但是当 activity 重新启动时,我得到 10 作为 LiveData
的值
我想不通原因。
我的第二个问题是我想保存 LiveData
的状态,它存储自定义 class
,保存时钟的状态
private val _timerState = MutableLiveData<TimerState>()
val timerState : LiveData<TimerState>
get() = _timerState
成为这个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()
}
但我没有成功,因为 TimerState
是自定义 class
而不是原始类型。
当您使用 SavedStateHandle
you need to set your values on it 来存储它们时。如果您对特定键使用 getLiveData
,那么只要您为该键设置新值,该 LiveData
就会更新。如果您直接在 LiveData
上设置它,您将绕过保存的状态:
class TimerViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
// create a LiveData that monitors this key in the saved state
private val _secondsRemaining = savedStateHandle.getLiveData<Long>(SECONDS_REMAINING)
val secondsRemaining : LiveData<Long> get() = _secondsRemaining
// expose a setter that updates the state - this will propagate to the LiveData
fun setSecondsRemaining(remaining: Long) {
savedStateHandle[SECONDS_REMAINING] = remaining
}
}
至于您的其他问题,是的,您可以存储的内容有限,对于自定义 classes,您要么需要 serialise them into a form you can store,要么将它们设为 Serializable
或Parcelable
.
但是在你的情况下,由于那个密封的 class 除了是一个类型的实例之外没有做任何特殊的事情,我只是把它变成一个枚举 class - 那些是 Serializable
所以你可以直接把值扔进去!
enum class TimerState {
OnFocusRunning, OnRestRunning // etc
}
根据 this 问题,我对我的应用程序做了一些简单的更改,但它没有像我预期的那样工作。
我有一个计时器,它会在计时器结束时发送通知。单击此通知会重新启动activity,删除所有定时器信息,主要存储在viewModel
中。出于这个原因,我决定使用 viewModel
.
这是我的 viewModel
:
class TimerViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
private val _secondsRemaining = savedStateHandle.getLiveData<Long>(SECONDS_REMAINING)
val secondsRemaining : LiveData<Long>
get() = _secondsRemaining
这是我在 Fragment
中使用 viewModel
的方法:
private val timerViewModel by viewModels<TimerViewModel>()
当我启动计时器时,我会在时钟的每个滴答声中将剩余的秒数保存在 LiveData
中。当计时器结束时,应用程序发送通知,计时器再次启动,计算一个新的周期:
timer = object : CountDownTimer(timerLengthSeconds * 1000, 1000){
override fun onFinish(){
(....)
}
override fun onTick(millisUntilFinished: Long) {
var secondsRemainingInCountdown = millisUntilFinished / 1000
(...)
_secondsRemaining.value = secondsRemainingInCountdown
}
}.start()
}
因此,当计时器结束时,应用程序会发送通知,但计时器已重新启动,剩余的秒数正在更新(我已通过日志检查过)。
当用户单击通知时,activity
被终止并重新启动,并且解释是查看计时器,剩余秒数保存在 LiveData
中。但是当 activity
重新启动时, LiveData
值为空。
我也尝试过将值设置为 10,以防 LiveData
在首次创建时为 null
private val _secondsRemaining = savedStateHandle.getLiveData<Long>(SECONDS_REMAINING, 10)
但是当 activity 重新启动时,我得到 10 作为 LiveData
的值我想不通原因。
我的第二个问题是我想保存 LiveData
的状态,它存储自定义 class
,保存时钟的状态
private val _timerState = MutableLiveData<TimerState>()
val timerState : LiveData<TimerState>
get() = _timerState
成为这个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()
}
但我没有成功,因为 TimerState
是自定义 class
而不是原始类型。
当您使用 SavedStateHandle
you need to set your values on it 来存储它们时。如果您对特定键使用 getLiveData
,那么只要您为该键设置新值,该 LiveData
就会更新。如果您直接在 LiveData
上设置它,您将绕过保存的状态:
class TimerViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
// create a LiveData that monitors this key in the saved state
private val _secondsRemaining = savedStateHandle.getLiveData<Long>(SECONDS_REMAINING)
val secondsRemaining : LiveData<Long> get() = _secondsRemaining
// expose a setter that updates the state - this will propagate to the LiveData
fun setSecondsRemaining(remaining: Long) {
savedStateHandle[SECONDS_REMAINING] = remaining
}
}
至于您的其他问题,是的,您可以存储的内容有限,对于自定义 classes,您要么需要 serialise them into a form you can store,要么将它们设为 Serializable
或Parcelable
.
但是在你的情况下,由于那个密封的 class 除了是一个类型的实例之外没有做任何特殊的事情,我只是把它变成一个枚举 class - 那些是 Serializable
所以你可以直接把值扔进去!
enum class TimerState {
OnFocusRunning, OnRestRunning // etc
}