内容简介:以注重生命周期的方式管理和界面相关的数据,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的作用域。
从图可以看出,在系统第一次调用Activity对象的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!界面酷炫、简单易用的数据库开源客户端
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Linux内核完全注释
赵炯 / 机械工业出版社 / 2005-8 / 42.00元
Linux内核完全注释,ISBN:9787111149682,作者:赵炯编著一起来看看 《Linux内核完全注释》 这本书的介绍吧!