MVVM出来有段时间了,MVVM由三部分构成 M:model数据 V:view视图 VM:viewModel 视图和数据双向绑定(通过dataBinding实现);今天介绍下如何一步步实现,到快速使用。
1在项目的build 的android节点里面 配置 dataBinding 的enabled为true
android {
//开启dataBinding
dataBinding{
enabled true
}
}
------------------------MVVM基本使用--------------------------------------
2创建一个viewModel对象 (就是我们平时的bean对象)
public class Bean {
private String name;
private String password;
public Bean(String name, String password) {
this.name = name;
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
3在布局使用laout标签为最外层标签 (注意layout不要配置宽高属性 不然build会报错)
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<!--注意layout不要配置宽高属性 -->
<!--data就是配置viewModel 即数据-->
<!--name 自定义 type为viewModel 类的全类名-->
<data>
<variable
name="bean"
type="cn.zdh.mvvm.viewModel.Bean" />
</data>
<!--布局代码-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{`姓名: `+bean.name}" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{`密码: `+bean.password}" />
</LinearLayout>
</layout>
4 在activity代码
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
//使用系统API绑定布局
//ActivityMainBinding是dataBinding build后生成的 名称是根据你的布局名称+Binding
ActivityMainBinding mainBinding=DataBindingUtil.setContentView(this,R.layout.activity_main);
//设置数据
mainBinding.setBean(new Bean("张三", "123"));
}
}
这样一个简单的MVVM的demo就实现了
------------------------------数据驱动视图变化-----------------------------------
1 MVVM是数据驱动UI,就是数据变了view就跟随变化,那怎么做到呢,修改下viewModel就可以
/**
* 实现 数据变化 视图实时跟随变化
* viewModel类 需要实现BaseObservable
* get 方法使用注解 @Bindable
* set 方法使用 notifyPropertyChanged(BR.对应属性名);注意先build下
*/
public class Bean extends BaseObservable {
private String name;
private String password;
public Bean(String name, String password) {
this.name = name;
this.password = password;
}
@Bindable
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
@Bindable
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
notifyPropertyChanged(BR.password);
}
}
2 在activity我们用代码模拟数据变化
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
//使用系统API绑定布局
//ActivityMainBinding是dataBinding build后生成的 名称是根据你的布局名称+Binding
ActivityMainBinding mainBinding=DataBindingUtil.setContentView(this,R.layout.activity_main);
//设置数据
final Bean bean = new Bean("张三", "123");
mainBinding.setBean(bean);
//代码设置5s后修改数据,看UI是否跟随变化
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
bean.setName("李四");
bean.setPassword("0000");
}
}, 5000);
}
}
这样就实现数据驱动视图变化了。
-----------------------自定义属性实现imageView 设置图片--------------------------
还是在viewModle里面使用注解 @BindingAdapter(bind:自定义属性名);注意方法需要 static修饰
/**
* 实现 数据变化 视图实时跟随变化
* viewModel类 需要实现BaseObservable
* get 方法使用注解 @Bindable
* set 方法使用 notifyPropertyChanged(BR.对应属性名);注意先build下
*/
public class Bean extends BaseObservable {
private String name;
private String password;
//自定义属性
private String phone;
@Bindable
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
notifyPropertyChanged(BR.phone);
}
public Bean(String name, String password, String phone) {
this.name = name;
this.password = password;
this.phone = phone;
}
@Bindable
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
@Bindable
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
notifyPropertyChanged(BR.password);
}
/**
* 自定义属性
* 使用注解 @BindingAdapter (如果括号使用bind: 括号里面 bind: 是固定写法 image是自定义属性名)
* 建议直接写属性名,要不会有警告
* getImage 方法名自定义
*/
@BindingAdapter("phone")
public static void getImage(ImageView imageView,String url){
Glide.with(imageView.getContext()).load(url).into(imageView);
}
}
----------------------------------------------------------------------实现点击---------------------------------------------------------------------------------------
在viewmodel 的Bean类添加下面方法
/**
* 点击
* clickImage方法名可以自定义 ,必须和xml的onclick 引用的一致
* 方法参数必须有view
*/
public void clickImage(View view) {
Toast.makeText(view.getContext(), "点击图片", Toast.LENGTH_SHORT).show();
}
在xml添加如下
<!--使用自定义属性以app开头 + 自定义属性名 ,没有提示build下-->
<!--实现点击效果只需要 在onClick属性里面 引用viewModel对应 定义的点击方法名-->
<ImageView
android:onClick="@{bean.clickImage}"
android:layout_width="match_parent"
android:layout_height="100dp"
app:phone="@{bean.phone}"/>
//注意 app后面的phone属性必须和自定义的属性 BindingAdapter括号里面一致,
//其他点击类似用法就不举例了。
源码:
--------------------------------mvvm如何使用插件轻松玩转viewModel ----------------------------------
下载插件databind generateAllFileSetter
//使用viewmodel继承BaseObservable;Alt +insert(Windows快捷键) 选择 DB getter and setter
//注意BR需要导包
//还不明白可以看使用详情 https://github.com/njleonzhang/DataBindingGetterSetter
//发现新插件 兼容4.0 GsonFormat4DataBinding 和GsonFormat一样用
-------------------------------MVVM的xml布局插件使用-------------------------------
下载插件Databinding Support
把光标放到顶层布局,Alt+回车选择convert to data binding layout
使用详情 https://plugins.jetbrains.com/plugin/9271-databinding-support
//还有另外个插件也是针对xml的 https://github.com/idisfkj/databinding_autorun