内容简介:以注重生命周期的方式管理和界面相关的数据,Jetpack为我们带来了ViewModel,从本文你可以学习到使用ViewModel的正确姿势。ViewModel被用来以注重生命周期的方式来保存数据和管理界面相关的数据。同时可以在相关配置发生变化是保存数据,例如屏幕旋转。由于Android framework管理着像Activity、Fragment这样具有生命周期的UI控制器,所以在用户的某些操作或者系统分发的某些事件,会导致framework在没有经过我们控制下,销毁和重建UI控制器。例如,屏幕发生旋转时,
以注重生命周期的方式管理和界面相关的数据,Jetpack为我们带来了ViewModel,从本文你可以学习到使用ViewModel的正确姿势。
一、ViewModel
ViewModel被用来以注重生命周期的方式来保存数据和管理界面相关的数据。同时可以在相关配置发生变化是保存数据,例如屏幕旋转。
由于Android framework管理着像Activity、Fragment这样具有生命周期的UI控制器,所以在用户的某些操作或者系统分发的某些事件,会导致framework在没有经过我们控制下,销毁和重建UI控制器。例如,屏幕发生旋转时,framwork会调用Activity的 onSaveIntanceState() 保存数据,在新Activity的 onCreate() 方法中恢复这些数据,不过这仅仅是恢复可序列化和反序列化的小数据上,像list或者bitmap这种大数据就不合适了。此外,也会导致大量已经存在的数据被销毁,然后重新生成,造成资源的浪费。
在 LiveData 也说到,不要在Activity和Fragment做大量的逻辑操作,会导致代码臃肿,难以维护,建议把相关逻辑抽到单独的类进行维护,让UI控制器负责它们的本质工作。
为此,使用ViewModel可以轻松解决以上问题。
1. 实现ViewModel
Architecture Components提供ViewModel工具类,用来为UI提供数据。ViewModel对象在配置发生变化时会自动保存数据,并且会在新建的Activity或Fragment实例使用。例如,在APP中需要显示持有多个user对象的list,应该将请求和保存users数据的动作在ViewModel对象实现,而不是Activity或Fragment。
class MyViewModel : ViewModel() {
private val users: MutableLiveData<List<User>> by lazy {
MutableLiveData().also {
loadUsers()
}
}
fun getUsers(): LiveData<List<User>> {
return users
}
private fun loadUsers() {
// Do an asynchronous operation to fetch users.
}
}
复制代码
在Activity中访问数据:
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Create a ViewModel the first time the system calls an activity’s onCreate() method.
// Re-created activities receive the same MyViewModel instance created by the first activity.
val model = ViewModelProviders.of(this).get(MyViewModel::class.java)
model.getUsers().observe(this, Observer<List<User>>{ users ->
// update UI
})
}
}
复制代码
当Activity被重建时,它会接收到来自第一个Activity的ViewModel对象,所以数据不会发生变化。当Activity销毁后,framework会自动调用ViewModel对象的 onCleared() 方法来进行释放资源。记得,ViewModel一定不要持有View、Lifecycle或者任何有Activity context对象的引用。因为ViewModel的生命周期比它们的长,会导致内存泄漏。如果ViewModel需要持有应用的conetxt,可以继承AndroidViewModel类,在它的构造方法中对接收应用的context。
2. ViewModel的生命周期
ViewModelProvider获取ViewModel对象时,ViewModel的生命周期作用域会传递给ViewModelProvider,ViewModel会一直保持在内存中,直到其生命周期作用域失效。在下面两种情况,ViewModel对象生命周期会失效:一种是Activity对象finished,一种是Fragment对象detached。
下图(图来自官网)显示了Activity的生命周期和ViewModel的作用域,第一列显示了Activity对象的状态,第二列显示Activity生命周期方法,第三列ViewModel的作用域。
onCreate() 方法,我们通常要在第一次时间创建ViewModel对象。在Activity对象的生命周期内,
onCreate()
方法可能由于系统配置改变而被系统调用多次,而ViewModel对象只有一次,ViewModel对象会一直存在直到Activity被终结和销毁掉。
3. 在Fragment之间共享数据
在实际开发中,经常会在两个或多个fragement对象共享数据,通常做法是实定义接口,由Activity绑定在fragment中。此外,Activity还要处理fragment的创建和可见的情况。
fragment之间可以在Activity的作用域内共享同个ViewModel对象来处理这个麻烦的数据交互问题。例如:
class SharedViewModel : ViewModel() {
val selected = MutableLiveData<Item>()
fun select(item: Item) {
selected.value = item
}
}
class MasterFragment : Fragment() {
private lateinit var itemSelector: Selector
private lateinit var model: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.run {
ViewModelProviders.of(this).get(SharedViewModel::class.java)
} ?: throw Exception("Invalid Activity")
itemSelector.setOnClickListener { item ->
// Update the UI
}
}
}
class DetailFragment : Fragment() {
private lateinit var model: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.run {
ViewModelProviders.of(this).get(SharedViewModel::class.java)
} ?: throw Exception("Invalid Activity")
model.selected.observe(this, Observer<Item> { item ->
// Update the UI
})
}
}
复制代码
由于两个Fragment对象绑定在同一个Activity对象,它们通过ViewModelProvider获取在Activity范围内的同一个ViewModel对象。
这样做的好处是:
- Activity对象不会感知两个Fragment对象的交互,所以也不用做任何事。
- Fragment对象不需要知道另外一个Fragment对象,除了和ViewModel的约定。当一个对象消失,另外一个对象还能正常使用。
- Fragment对象的生命周期不受其他的对象影响,一个Fragment对象替换另一个,UI还能正常运行。
4. ViewModel替代Loader
加载器类像CursorLoader,经常用来保持UI中的数据与数据库的同步。可以通过ViewModel,和其他的类,替换Loader类。使用ViewModel分离UI控制器的数据加载动作,意味着可以减少更多的类强引用。 使用Loader一个常见的方法,就是在应用程序中使用一个CursorLoader观察的数据库内容,当数据库的值发生变化时,Loader自动重新加载数据和更新用户界面:
使用ViewModel,并和Room或LiveData一起代替Loader。ViewModel对象在配置发生变化是保持数据,而Room通知LiveData数据库数据改变,LiveData则将修改后的数据更新到UI上。
总结
Jetpack讲到这里,基本都明白Jetpack是干嘛了,Jetpack总结我们平常开发的各种效率和架构,为我们提供更标准的组件。Room操作数据库,LiveData通知数据更改,DataBinding更新View,Lifecycle管理周期,及其后面要讲的其他组件。都在给我们应用层开发定义一套统一开发架构标准,以便可以开发更好APP。通过这么一套架构组件,可以快速开发可维护性高,扩展性好的APP。
本文是Jetpack系列文章第四篇
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 前嗅ForeSpider数据建表和高级配置界面介绍
- JeeSite v4.2.3 发布,前后数据差异分析、界面优化、细节优化
- Qt编写数据可视化大屏界面电子看板1-布局方案 原
- bg.work 权限管理实现完成,数据操作/界面显示控制更便捷
- usql 0.7.0 发布,SQL 数据库的通用命令行界面
- 1.5 万 star!界面酷炫、简单易用的数据库开源客户端
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Big Java Late Objects
Horstmann, Cay S. / 2012-2 / 896.00元
The introductory programming course is difficult. Many students fail to succeed or have trouble in the course because they don't understand the material and do not practice programming sufficiently. ......一起来看看 《Big Java Late Objects》 这本书的介绍吧!