Android 中带有 SavedState 的 ViewModel
谷歌在谷歌 I/O 2018 上推出了 Android Jetpack,这是一套用于创建优秀 Android 应用程序的组件、工具和指南。它包括 LiveData、ViewModel、Room Database、Work Manager 和其他组件。 ViewModel 将在本博客中讨论。在Activity生命周期中,ViewModel维护着UI相关的数据。它使应用程序能够承受配置更改(如屏幕旋转)。
ViewModels 主要用于,
- 为用户界面层准备数据。
- 处理应用程序轮换配置。
如何添加视图模型
Kotlin
class gfgViewModel : ViewModel() {
val courses = MutableLiveData>()
fun getCourses(): LiveData> {
return courses
}
private fun loadCourses() {
courses.value = // courses provided by gfg
}
}
Kotlin
class GeeksActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Starting the model
val gfgSampleModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
gfgSampleModel.getCourses().observe(this, Observer>{ courses ->
// do something like UI update
})
}
}
Kotlin
val gfgSamplemodel = ViewModelProviders.of(this).get(GeeksModel::class.java)
Kotlin
gfgModel.getCourses().observe(this, Observer>{ courses ->
// Do something here
}
Kotlin
class GeeksVM(private val savedStateHandle: SavedStateHandle) : ViewModel(), BaseViewModel {
override fun getCoursename(): LiveData {
return savedStateHandle.getLiveData(Constants.COURSE)
}
override fun saveCourse(username: String) {
savedStateHandle.set(Constant.COURSE, course)
}
}
Kotlin
interface gfgViewModel {
fun getCoursename(): LiveData
fun saveCourse(username: String)
}
然后将数据导入到视图中,
科特林
class GeeksActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Starting the model
val gfgSampleModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
gfgSampleModel.getCourses().observe(this, Observer>{ courses ->
// do something like UI update
})
}
}
我们必须使用以下方法在视图(活动/片段)中初始化 ViewModel,
科特林
val gfgSamplemodel = ViewModelProviders.of(this).get(GeeksModel::class.java)
现在我们可以在 UI 中看到数据:
科特林
gfgModel.getCourses().observe(this, Observer>{ courses ->
// Do something here
}
这就是在我们的视图中使用 ViewModel 的方式。可以在此处找到有关 ViewModel 的更多信息。现在我们可以改变,但它是受限制的。为了管理它,我们可以使用 onSaveInstanceState() 返回到之前的状态。
每个 Android 应用程序都在其自己的 Linux 进程中运行,这被描述为系统启动进程死亡。当必须执行其部分代码时,该进程由程序启动,并且它将继续运行直到不再需要并且系统需要恢复其内存以供其他应用程序使用。
GeekTip: If your program is not in the forefront, the system can stop it at any time to free up system RAM for other processes to use.
- 配置和系统启动的进程死亡都可以由 onSaveInstanceState() 包处理。
- 但是,它只能容纳有限数量的数据,并且高度依赖于速度和存储,因为序列化需要大量内存来存储数据。
- 序列化发生在主线程上,因此当配置发生变化时,UI 屏幕可能会被阻塞,并且应用程序也可能会死机( ANRs),即 App Not Responding。
- onSaveInstanceState()只能保存少量数据。
ViewModel 的保存状态
因为UI数据总是从架构组件的ViewModel而不是View(Activity/Fragment)引用,所以ViewModel的Saved State可以看作是onSaveInstanceState()的替代。所以我们必须执行一些代码来利用 onSaveInstanceState()。
因此,作为 Jetpack 的一部分,Google 推出了 Saved State,它允许我们在数据被 System Initiated Process Death 杀死后保留和恢复已保存状态的数据。
GeekTip #2: It should be noted that the state must be basic and lightweight. Local persistence should be used for complicated or big data sets.
将以下代码添加到您的构建中以在 Project 中集成 Saved State。
implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:1.0.0-alpha01'
如何使用 Saved State?
在您的视图(活动/片段)的 onCreate()函数中替换以下代码片段。
val model = GeeksViewModel.of(this, savedVMState(this)).get(MainGfGViewModel::class.java)
代替:
val gfgModel= GeeksViewModel.of(this).get(MainGfGViewModel::class.java)
此外,在 ViewModel 中:
class GeeksViewModel(private val state: SavedStateHandle) : ViewModel() { ... }
如您所见,我们向 ViewModel 的主函数Object() { [native code] } 提供了 SavedStateHandle。为了获得 SavedStateHandle,我们在 ViewModelProviders.of 中使用 SavedStateVMFactory() 作为工厂。
GeekTip #3: A Factory is an Interface that instructs the ViewModel on how to construct the ViewModel.
请注意,它只是一个键值对。即使程序因系统启动进程死亡而死亡,数据仍将被保存。
如您所见,我们向 ViewModel 的主函数Object() { [native code] } 提供了 SavedStateHandle。为了获得 SavedStateHandle,我们在 GeeksViewModel.of 中使用 savedVMState() 作为工厂。
工厂是指示 ViewModel 如何构造 ViewModel 的接口。
- 即使程序因系统启动进程死亡而死亡,数据仍将被保存。
- SavedStateHandle 与 Android 中的 SharedPreferences 类似,因为它对键值对进行操作。
- 让我们看一个例子:我们将创建一个包含三个 UI 组件(EditText、Button 和 TextView)的应用程序。
- 当用户在 EditText 中输入他们的用户名并单击 Button 时,用户名应显示在 TextView 中
MainViewModel 现在应该是这样的,
科特林
class GeeksVM(private val savedStateHandle: SavedStateHandle) : ViewModel(), BaseViewModel {
override fun getCoursename(): LiveData {
return savedStateHandle.getLiveData(Constants.COURSE)
}
override fun saveCourse(username: String) {
savedStateHandle.set(Constant.COURSE, course)
}
}
这里,
- 数据使用savedStateHandle.set("Key","Value") 存储。
- 保存状态 handle.get live data(“key”) 方法用于检索 String 数据类型的 LiveData。
MainViewModel 类实现了 BaseViewModel,它看起来像这样。
科特林
interface gfgViewModel {
fun getCoursename(): LiveData
fun saveCourse(username: String)
}
验证
执行步骤 – #1,您将不会在控制台中看到您的应用程序包名称。
当您重新打开程序时,您应该会看到输出持续存在并显示在屏幕的 TextView 中。
重要笔记:
如果您希望保留数据,请使用savedState。
savedStateHandle.set("key_name","value")
如果您希望从savedState 检索数据,请使用以下语法:
savedStateHandle.get("key_name")
如果您希望获得 LiveData 作为返回类型,请使用。
savedStateHandle.getLiveData("key_name")
如果要查看savedState 中是否存在某个键,请使用以下代码。
savedState.contains("key_name")
如果您想在savedState 中找到所有键,请使用以下命令获取它们的列表。
savedState.keys()
您还可以通过键访问它来删除任何单个值。执行以下操作:
savedState.remove("key_name")