ViewModel如何使用
这篇文章主要介绍“ViewModel如何使用”,在日常操作中,相信很多人在ViewModel如何使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”ViewModel如何使用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
1 主要功能
Activity、Fragment存活期间的数据存储;
bind同一Activity的多个Fragment间数据共享;
独立或与LiveData配合实现代码解耦;
2 使用方法
1) 引入ViewModel
在build.gradle中添加编译lifecycle.extensions module,该module同时包含ViewModel和LiveData:
compile('android.arch.lifecycle:extensions:1.0.0')
由于lifecycle.extensions内部依赖26.1.0版本的support_v7包,建议将工程中已引用的support_v7组件版本也升级到26.1.0或以上。
2) 构造数据对象
自定义ViewModel类,继承ViewModel;
在自定义的ViewModel类中添加需要的数据对象;
public class DemoViewModel extends ViewModel { final public DemoData mData = new DemoData(); public DemoViewModel() {} }
3) 获取数据
通过ViewModelProviders和Activity / Fragment获取ViewModelProvider;
通过ViewModelProvider和自定义ViewModel类获取自定义ViewModel对象;
从自定义ViewModel对象获取数据对象,进行需要的读写操作。
DemoData data = ViewModelProviders.of(getActivity()) .get(DemoViewModel.class) .mData; data.doSth();
3 使用场景示范
1) 单Activity多Fragment间数据维护
需求点:
bind同一个Activity的Fragment A、B;
Fragment A、B间存在跳转关系;
Fragment A、B共同维护一些数据,且A、B均有读取、修改的业务需求;
传统实现方法1:Intent +onFragmentResult()
大致流程:跳转时需要将数据按k-v封装入Bundle,或者将数据Parcelable传递给下个页面;
下个页面修改数据并返回后,需要从onFragmentResult()的Intent解析并同步数据;
Intent传递的数据大小总量不能超过1M;
麻烦且数据大小有限制。
传统实现方法2:数据对象SingleInstance、static
缺点:数据的生命周期要自行控制;
容易内存泄漏;
同样麻烦,且有一定风险。
ViewModel同时规避了传统方法的缺点:
bind同一个Activity的Fragments均可以通过ViewModelProvider获取共同的数据对象,无需主动进行数据传递;
脱离Intent、Bundle、Parcelable这些用起来很麻烦的控件;
数据生命周期由ViewModel内部掌控,无需手动管理销毁;
2) 与LiveData配合实现UI、业务逻辑分层
同为官方架构组件的LiveData,功能是监听数据变化,并回调给注册的observer。ViewModel+LiveData可以很方便的抽象出数据层和业务层,快速解耦。
下面的Demo来自官方案例。通过Demo,以及LiveData、ViewModel同处一个module,可以看出官方非常建议两者搭配使用。再配合以往的Data-Binding,可以快速搭建起一套简易的MVVM业务体系。
public class MyViewModel extends ViewModel { private MutableLiveData<List<User>> users; public LiveData<List<User>> getUsers() { if(users == null) { users= new MutableLiveData<List<Users>>(); loadUsers(); } return users; } private void loadUsers() { //Do an asyncronous operation to fetch users. } } public class MyActivity extends AppCompatActivity { public void onCreate(Bundle savedInstanceState) { //Create a ViewModel the first time the system calls an activity's onCreate()method. //Re-created activities receive the same MyViewModel instance created by thefirst activity. MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class); model.getUsers().observe(this,users -> { //update UI }); } }
4 生命周期特性
ViewModel的生命周期与Lifecycle同步,当Activity /Fragment超出Lifecycle范围(并不是onDestroy()回调),ViewModel连同其包含的数据一起被销毁了。具体有多大呢,按照官方说法:
in the case of an activity, when it finishes, whilein the case of a fragment, when it’s detached.
Activity退栈后(Fragment则是与Activity解除关系后),ViewModel就解除引用关系,准备被系统回收了。
5 源码分析
带着两个小问题简单的进行下源码分析:
1) ViewModel与Activity / Fragment的映射关系是如何建立起来的?
(以Activity为例)
第一部分:获取ViewModelProvider
调用ViewModelProviders.of(Activity);
一路调用,最终走到HolderFragmentManager.holderFragmentFor(Activity);
HolderFragmentManager依次从FragmentManager和HolderFragmentManager持有的HashMap查找:该Activity是否有HolderFragment与之映射(HolderFragment的作用下面一个问题将谈到);
HolderFragment.class HolderFragment holderFragmentFor(FragmentActivity activity) { FragmentManagerfm = activity.getSupportFragmentManager(); HolderFragment holder = findHolderFragment(fm); if(holder != null) { return holder; }else { holder = (HolderFragment)this.mNotCommittedActivityHolders.get(activity); if(holder != null) { return holder; }else { //创建HolderFragment
有则返回该HolderFragment;没有则创建一个HolderFragment:
新建一个HolderFragment,commit给FragmentManager,并存入HashMap以标记为not committed状态,防止重复commit;
向Application注册对该Activity的生命周期监听。如果HolderFragment尚未create,Activity就已经销毁,则从HashMap中移除该Activity,防止泄露;
HolderFragment成功创建后,从HashMap中移除该Activity;
使用HolderFragment持有的ViewModelStore对象完成ViewModelProvider的创建;
第一部分的职责是构建 / 查找HolderFragment,对构建过程中的异常做保护,最后返回ViewModelProvider。HolderFragment和ViewModelProvider共同持有的ViewModelStore将成为第二部分的核心;
(第二部分:获取ViewModel)
调用ViewModelProvider.get(ViewModel.class);
通过ViewModel的规范名(canonical name),从HashMap中查找是否已经存在该ViewModel的实例。有则返回;没有则通过反射构建一个,并存入HashMap;
ViewModelStore.class public class ViewModelStore { private final HashMap<String, ViewModel> mMap = new HashMap();
第二部分职责是映射,通过类名从HashMap查找ViewModel实例。整个映射逻辑也可以简化为:通过Activity类名找ViewModel实例;
2) ViewModel的生命周期如何管理?
ViewModel objects are scoped to the Lifecycle passed to the ViewModelProvider when getting the ViewModel.
看到官方文档中的这句话,心想ViewModel莫非是通过同为官方架构组件的Lifecycle来管理的生命周期的?
其实并没有那么复杂,ViewModel在第一次调用ViewModelProvider.get(ViewModel.class)创建;而销毁就需要靠HolderFragment自己的onDestroy()回调:
HolderFragment.class public void onDestroy() { super.onDestroy(); this.mViewModelStore.clear();}
ViewModelStore.class public final void clear() { Iteratorvar1 = this.mMap.values().iterator(); while(var1.hasNext()){ ViewModel vm = (ViewModel)var1.next(); vm.onCleared(); } this.mMap.clear(); }
HolderFragment销毁后,调用ViewModelStore.clear(),清理HashMap对ViewModel对象的引用,待系统GC回收ViewModel。这也解释了创建ViewModelProvider时为什么需要HolderFragment配合,HolderFragment掌控了ViewModel的生命周期。
6 Last but not least
简述下官方架构中各组件的主要职责:
Lifecycle:将Activity /Fragment生命周期回调事件向外抛出;
LiveData:在Lifecycle范围内监听数据的变化;
ViewModel:在Lifecycle范围内存储和共享数据;
Room:简化Db操作;
除了Room,可以感受到官方在尽力把大家从最初的MVC往MVVM引导,更加强大的官方组件将使UI-业务-数据的抽象过程变得更加简单顺滑。
到此,关于“ViewModel如何使用”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341