android - 在应用进程被杀死之前,如何在 ViewModel 的 onCleared 方法中为 SavedStateHandle 提供的 LiveData 设置特定值
问题描述
在我的个人项目中,我使用 Hilt(依赖注入)、SavedStateHandle 和 ViewModel。
SavedStateHandle 允许我在进程死亡时保存数据。
因为 ViewModel 在进程死亡后无法生存,所以我使用 Hilt 注入在 ViewModel 中注入了 savedStateHandle 对象。
当使用 coroutines/viewModelScope 处理 http 请求时,我使用自定义类“ViewState”来处理从 UI 观察到的一个 LiveData 中的多个状态。
例如:LiveData<ViewState<User>>
然后在 UI 中,我绑定了 viewState:viewMvc.bind(userViewState)
sealed class ViewState<T> : Serializable {
data class Loading<T>(@Transient val job: Job? = null, val oldResult: T? = null) : ViewState<T>(), Serializable
data class Fetched<T>(val result: T, val fetchedDate: Date = Date()) : ViewState<T>(), Serializable
data class Error<T>(val e: Exception, val oldResult: T? = null) : ViewState<T>(), Serializable
override fun toString(): String {
return when (this) {
is Loading -> "ViewState.Loading - oldResult: $oldResult"
is Fetched -> "ViewState.Fetched - result: $result, fetched date: $fetchedDate"
is Error -> "ViewState.Error - class: ${e::class.java.simpleName}, message: ${e.localizedMessage?.toString()}"
}
}
fun lastResult(): T? {
return when (this) {
is Fetched -> result
is Loading -> oldResult
is Error -> oldResult
}
}
}
在 ViewState.Loading 类中,作业是瞬态的,因为它不可序列化。而且在 viewModel 中使用 SavedStateHandle 之前,我不需要序列化 LiveData 值,因为它在创建 ViewModel 时被初始化为 null。
问题是
当应用程序进程在用户的 viewState 为 ViewState.Loading 时被杀死时,viewModelScope 不再处于活动状态,并且与其关联的作业在 ViewModel 的 onCleared() 中被取消。
天真地,我认为当“onCleared”事件发生时,我必须将 LiveData 的值更改为 null 或任何我想避免 ViewState.Loading 值跨进程死亡但显然 SavedStateHandle 此时已经保存;因为否则当应用程序状态恢复时,用户视图状态是 ViewState.Loading() 并且我正在等待由于作业已经取消而永远不会发生的事情。序列化 SavedStateHandle 时,我永远不应该保存 ViewState.Loading 对象。所以在实践中“工作”变量不应该是瞬态的,因为它永远不会被序列化。
如何截取 SavedStateHandle 被序列化/打包的确切时间以避免此类问题?
解决方案
我想你不能(除非你在活动/片段中自己保存/恢复)。
但是,您可以在还原后绕过它,而不是阻止存储加载状态。例如,当您恢复的状态为正在加载时,您可以再次调用加载函数。
// Inside your viewModel
init{
if(savedState.contains("Loading)){
viewModelScope.launch{
loadData()
}
}
}
推荐阅读
- python - Pandas Dataframe:如何获取整个数据帧的真实部分?
- twitter-bootstrap - 尝试在 Bootstrap 中使用 Toggler 但它不起作用
- java - Spring AbstractAuthenticationFailureEvent 不起作用。身份验证失败时
- robotframework - 有没有其他方法可以用第一个答案来解决这个问题?
- python - 覆盖多选 BooleanField 请求响应 django
- openstack - 如何在 openstack trove 中创建 percona 实例或 Percona XtraDB Cluster?
- oracle - CREATE ANY TABLE 不足以创建任何表?
- c# - itext 7页面删除C#的奇怪问题
- storybook - 故事书 argType 和 defaultValue 在侧边栏中更改视图时选择丢失值
- oracle-sqldeveloper - Oracle Apex 中的自定义访问角色