前言:最近在面试中被问到MVVM与MVP的区别,才发现自己对MVVM还是有误解
先说说MVP跟MVVM的区别吧
MVP:
MVP全名是Model-View-Presenter。
View:UI模块,负责界面显示和与用户交汇。
Presenter:负责业务逻辑,起着连接View和Model桥梁的作用。
Model:专注于数据逻辑。
为了解决MVC中代码的耦合严重性,把业务逻辑都抽离到了Presenter中。这样View和Model完全被隔离实现了单向依赖,大大减少了耦合度。view和prensenter之间通过接口来通信。
优点:
- 模型与视图完全分离,我们可以修改视图而不影响模型;
- 可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部;
- 我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。
- 如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)
MVVM:
MVVM,全名为Model-View-ViewModel
- View:和前面的MVP、MVC中的View一样,负责UI界面的显示以及与用户的交汇。
Model:同样是负责网络数据获取或者本地数据库数据获取。 - ViewModel:负责存储view的数据映像以及业务逻辑。
MVVM的viewModel通过将数据和view进行绑定,修改数据会直接反映到view上,viewModel是绑定于单独的view的,也就不需要进行编写大量接口了。但viewModel中依旧有很多的业务逻辑,但是因为把view和数据进行绑定,这样可以让view和业务彻底解耦了。view可以专注于UI操作,而viewModel可以专注于业务操作。
View只需要关注ViewModel的数据部分,而无需知道数据是怎么来的;而ViewModel只需要关注数据逻辑,而不需要知道UI是如何实现的,彻底把业务和UI逻辑进行解耦。
缺点:
MVVM的viewModel很臃肿。
MVVM需要学习数据绑定框架,具有一定的上手难度。
google推荐使用上手难度相对较低的mvvm + JetPack框架去解决这两个问题。
MVVM代码实现
这里使用databinding在xml中插入数据来实现
在build.gradle中添加依赖配置:
buildFeatures {
viewBinding = true
}
dataBinding {
enabled = true
}
首先定义一个数据类型Bean类,然后用alt+Insert快捷键来进行set跟get方法注入
public class LateDateWeatherBean {
private String dayTime = "";
private String dayWeek = "";
private int conditionImageResource = 0;
private String tempLow = "";
private String tempHeight = "";
}
接着定义一个xml,光标落在首行 Alt+Enter会提示插入data标签,alias 是别名,type是类型
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="com.example.myapplicationcalculator.LateDateWeatherBean" alias = "dayBean"/>
<variable
name="day"
type="dayBean" />
</data>
</layout>
接着就可以使用@{}来插入指定的数据了
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp">
<TextView
android:id="@+id/tvDayAfterOneDay"
android:text="@{day.dayTime}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="@color/colorBackGround"
android:textSize="20dp"
android:textStyle="normal|bold" />
</LinearLayout>
接着定义一个adapter并在内部定义一个静态holder,在holder内部定义一个bind方法去向xml中插入数据
实现RecycleView.Adapter的三个方法,在bindView中去绑定数据
定义Recycle所在布局的视图Binding
private ActivityWeatherBinding activityWeatherBinding;
在activity的onCreate中初始化并渲染
activityWeatherBinding = ActivityWeatherBinding.inflate(getLayoutInflater());
setContentView(activityWeatherBinding.getRoot());
在Activity中加载RecycleView,lateDaysList是LateDateWeatherBean类型的数据列表
dayAdapter = new DayAdapter(lateDaysList);
activityWeatherBinding.dayRecycle.setLayoutManager(new LinearLayoutManager(WeatherActivity.this));
activityWeatherBinding.dayRecycle.setAdapter(dayAdapter);
最后使用ViewMode加载数据
1.定义一个ViewMode
public class DaysViewModel extends ViewModel {
private MutableLiveData<List<LateDateWeatherBean>> mutableDayList;
public LiveData<List<LateDateWeatherBean>> getDaysLiveData() {
if (null == mutableDayList) {
mutableDayList = new MutableLiveData<>();
}
return mutableDayList;
}
public void setDays(List<LateDateWeatherBean> days) {
if (null == mutableDayList) {
mutableDayList = new MutableLiveData<>();
}
mutableDayList.setValue(days);
}
}
之后在onCreate中创建viewMode实例并刷新布局
daysViewModel = new ViewModelProvider(this).get(DaysViewModel.class);
daysViewModel.getDaysLiveData().observe(WeatherActivity.this, (Observer<List<LateDateWeatherBean>>) lateDateWeatherBeans -> {
if (lateDateWeatherBeans.size() > 0) {
dayAdapter = new DayAdapter(lateDateWeatherBeans);
activityWeatherBinding.dayRecycle.setLayoutManager(new LinearLayoutManager(WeatherActivity.this));
activityWeatherBinding.dayRecycle.setAdapter(dayAdapter);
}
});
最后在获取到数据列表后设置数据就完成MVVM双向绑定数据了
daysViewModel.setDays(lateDaysList);
源码连接:
https://github.com/xzq199946/Multifunctional.git
参考连接:
https://zhuanlan.zhihu.com/p/644313698
https://www.nowcoder.com/discuss/393521436973957120
https://zhuanlan.zhihu.com/p/623848614