Android 使用Google官方组件搭建 MVVM架构
概述
MVVM架构在MVP结构上,将Presenter改为ViewModel,使用ViewModel与View进行(DataBinding—>双向?)绑定,当ViewModel的数据发生更改,自动反映到View中显示;
反之,当View对数据更改时,ViewModel的数据也会随之变化。
View: 对应于Activity和XML,负责View的绘制以及与用户交互。 Model: 实体模型。 ViewModel: 负责完成 View与Model间的交互,负责业务逻辑。
初识Android MVVM 时,百度搜到一大堆DataBinding数据绑定的文章,很容易陷入泥潭。
事实上,DataBinding 只是实现数据和UI双向绑定的框架,是构建MVVM模式的一个工具,可以单独使用在任何架构中,也可以在MVVM中使用,增加代码简洁性。
ViewModel
ViewModel类旨在存储和管理用户界面相关的数据生命周期中的方式,在ViewModel类中当屏幕旋转配置更改时允许数据能够被保存。
比如:在一个Activity中包含一个用户的表单数据。当Activity为改变配置重新创建时(屏幕旋转为例),新建的Activity会重新获取用户的数据。对于简单的数据可以保存在onSaveInstanceState()方法并在onCreate()中通过bundle获取数据,但是这种方式只适合少量数据的序列化和反序列化,对于大量的表单数据或者图片不适用。
-
SavedState 会经由System Server(一个独立的进程)保存内容(序列化的数据),也就是说,他会无视应用进程的存在。
UI的状态记录,比如选择区域和滚动距离。
导航状态键值记录。
异常终止时保存数据
-
而ViewModel则一直运行在应用进程中,即便应用的配置发生变化,只要进程还在,ViewModel保存的内容就不会消失。但只要进程消失。ViewModel的内容也会消失。
保留应用对于网络、数据库的请求。
当作大型数据的缓存。
-
ViewModel层只做和业务逻辑和业务数据相关的事请,不做任何UI操作。ViewModel层不会持有任何控件的引用,更不会在ViewModel中通过UI控件的引用去更新UI
-
ViewModel 的生命周期:
注意:
-
任何时候都不要将Context传入ViewModel;
-
如果要在ViewModel中使用Application实例,请使用 AndroidViewModel 子类;
-
当进程关闭时,ViewModel会被销毁,而onSaveInstanceState不会受影响,所以用SavedState
存储少量关键数据,并在场景恢复后用来加载页面数据。
View
View层不做任何逻辑业务、不涉及操作数据、不处理数据、将UI和数据严格地分开。
- View层主要负责和UI相关的工作,我们只在XML、Activity和Fragment中写View层的代码,View层不做任何业务相关的事情;
- 更新UI通过数据绑定实现,尽量在ViewModel里面做,即更新绑定的数据源即可;
- Activity中做初始化一些控件的工作;
Model
Model层最大的特点是被赋予了数据获取的职责,与平常Model层只是dinginess实体对象的行为截然不同。
实际中,数据的获取、存储、数据状态变化都是Model层 的工作。
- Model层包括实体模型(Bean)、Retrofit的Service,获取网络数据的接口,本地存储(增删改查)接口,数据变化监听等。
- Model层提供数据接口供ViewModel调用,经过数据转换并最终映射绑定到View层某个UI元素的属性。
协同合作
LiveData
LiveData是一个可观测数据的容器类。LiveData能够感知Activtiy、Fragment或者Service的生命周期,因此,LiveData确保了只有在这些组件处于活动状态的时候才会更新他们。
-
确保UI和数据的状态保持一致
LiveData符合观测者的行为规则。当生命周期的状态产生变化时,他就会通知Observer对象。
LiveData的观测者会在每次数据产生变化时更新UI,从而我们无需再数据变化的每个地方添加更新UI的代码。
-
不会内存泄漏
观测者受到LifeCycle的作用域限制,并且会在与其关联的生命周期被销毁后自动清理自己。
-
资源共享
-
无需管理生命周期
创建 LiveData 对象
public class NameViewModel extends ViewModel {
// 创建一个存储 String 的 LiveData 对象
private MutableLiveData<String> mCurrentName;
public MutableLiveData<String> getCurrentName() {
if (mCurrentName == null) {
mCurrentName = new MutableLiveData<String>();
}
return mCurrentName;
}
// ViewModel 的其余部分……
}
在初始状态,LiveData
对象中的数据没有被赋值。
注意:请务必将更新UI的LiveData对象存储在ViewModel对象中,而并非Activtiy或者Fragment。
原因如下:
- 避免过于臃肿的 Activity 和 Fragment 。这些UI控制器仅仅负责展示数据,而非存储数据。
- 将 LiveData 实例从特定的Activity或Fragment中解耦出来,并允许LiveData存活周期更长(例:activity配置更改时)。
观察 LiveData 对象
通常,我们应当在某个应用组件的 **onCreate() **方法中对设置对 LiveData 对象的观察。
- 确保系统不会因为执行 activity 或 fragment 的 onResume() 方法而导致重复调用观察。
- 确保 activity 或 fragment 能在进入活动状态时尽快获得用于展示 UI 的数据。
一般而言,LiveData 只有在数据变化的情况下才会将更新通知给活动状态的观察者。如果观察者又一次从非活动状态进入活动状态,那么只有当数据在这期间又发生变化,观察者才会收到更新。
LiveData只能在生命周期active下发送数据给观察者,Activity处于后台(inactive)时,即使LiveData收到了新的数据,也不会通知Activity;但是当Activity重新返回到前台(active)会受到新的数据。如我们所说,LiveData是粘性的。
public class NameActivity extends AppCompatActivity {
private NameViewModel mModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);