MVVM的学习

最近在学习MVVM,阅读了一些相关的文章,自己做了总结。

MVVM是什么?

MVVM它分为三个层:

  • Model:数据模型,对数据进行处理
  • View:UI展示,包括Activity、Fragment等
  • ViewModel:View和Model之间的桥梁,处理界面逻辑,让View和Model之间进行交互。
    这里写图片描述

为什么要有MVVM?

现在使用的基本是MVP或是MVC,最开始觉得MVP已经很好了,因为它通过Presenter把View和Model分隔开来,很大程度减低耦合性。但是慢慢发现MVP也存在着它的不足:
- 接口多,而且粒度不好控制,分太小接口会很多,分太大代码又会很多。
- View层上的某个UI可能变更,数据映射到UI上可能也要跟着改变
- P层可能会随着业务的增多而代码变多,View的方法也可能变多。这可能会导致他们依然会产生臃肿。
而MVVM的特点就是:
- 可重用性:View的视图逻辑放在ViewModel中,多个View可重用这些视图逻辑
- 双向绑定:可直接在布局中填充数据,而不用去获取View的实例再去setter。

说到MVVM,当然少不了DataBinding

介绍

DataBinding是谷歌提供的一个框架,它让我们省去了许多findViewById和View设置数据的操作。

使用

  • 在build.gradle文件中的android下添加dataBinding{enabled=true}
  • 准备好数据模型:
public class User extends BaseObservable{
    private String name;
    private int arg;

    public User(String name, int arg) {
        this.name = name;
        this.arg = arg;
    }
    @Bindable
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(BR.name);

    }
    @Bindable
    public int getArg() {
        return arg;
    }

    public void setArg(int arg) {
        this.arg = arg;
        notifyPropertyChanged(BR.arg);
    }
}

加上注解和notifyPropertyChanged(BR.xxx)是为了绑定的实体改变时布局中的数据跟着改变,还有另一种更方便的

public class Other {
    //效果和User的@Bindable+notifyPropertyChanged(BR.xxx)相同
    //通过set改变数据进而布局中绑定的数据跟着改变
    public final ObservableField<String> name = new ObservableField<>();
    public final ObservableField<Integer> age = new ObservableField<>();
}
  • 在布局文件中绑定数据
<layout xmlns:android="http://schemas.android.com/apk/res/android">
//在layout标签中导入User
<import
    alias="aUser" <!—别名,防止类名重复-- >
    type="com.sendi.mvvmdemo.bean.User"/>
<variable
    name="user"
    type="aUser"/>
    //绑定数据:
    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:gravity="center"
    android:text="@{user.name}" <!—绑定User类的name属性 -- >
    android:textColor="#000000"
    />
</layout>
  • 绑定点击事件
    Java代码
public class MyClick {
    public void onChangeAge(View view){//次点击方法必须是public void 并且参数为View
        Toast.makeText(view.getContext(), "click me!", Toast.LENGTH_SHORT).show();
    }
}

布局文件

<variable
    name="myClick"
    type="com.sendi.mvvmdemo.MyClick"/>

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="changeAge"
    android:onClick="@{myClick.onChangeAge}"
    />
  • 图片的显示
    Java类
public class ImageUtil {
//此方法要static,上边主节点参数为布局文件中的属性(第二个参数可换成别的类型)
    @BindingAdapter({"image"})
    public static void imageLoader(ImageView imageView,int imageId){
        imageView.setImageResource(imageId);
    }
}

布局文件中

<ImageView
    android:layout_width="60dp"
    android:layout_height="60dp"
    image="@{imgId}"
    />
接下来是设置绑定
  • 数据显示
//获取Binding
ActivityMainBinding mBinding
        =DataBindingUtil.setContentView(this,R.layout.activity_main);
//设置要显示的数据实体
User mUser= new User(”asendi”,21)  
mBinding.setUser(mUser);

这样数据就显示到界面中。

  • 动态改变数据
mUser.setAge(22);
//只要修改User对象,此时界面会跟着改变年龄的显示
  • 点击事件
mBinding.setMyClick(new MyClick());
//这样点击事件便失效了
  • 设置图片
mBinding.setImgId(R.mipmap.bg);//设置图片资源
  • 列表
    • 这里用RecyclerView为例子,在布局中的RecyclerView与往常一样
mBinding.recyclerView //这样便是获取到RecyclerView的实例,而不需要去FVB;其中recyclerView是在布局中的id

item布局文件:

<?xml version="1.0" encoding="utf-8"?>
<layout>
    <data>
        <variable
            name="user"
            type="com.sendi.mvvmdemo.bean.User"/>
    </data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="wrap_content">
<TextView
    android:id="@+id/name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{user.name}"
    />
    <TextView
        android:id="@+id/age"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{user.age}"
        />
</LinearLayout>
</layout>

适配器:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyHolder> {
    private List<User> mUserList = new ArrayList<>();

    public MyAdapter() {}

    public void refresh(List<User> userList) {
        mUserList = userList;
        notifyDataSetChanged();
    }

    @Override
    public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return MyHolder.create(
                LayoutInflater.from(parent.getContext()),parent);
    }

    @Override
    public void onBindViewHolder(MyHolder holder, int position) {
        holder.bindTo(mUserList.get(position));
    }


    @Override
    public int getItemCount() {
        if (mUserList==null)
            return 0;
        return mUserList.size();
    }

    static class MyHolder extends RecyclerView.ViewHolder {

        private UserItemBinding mItemBinding;

        public MyHolder(UserItemBinding binding) {
            super(binding.getRoot());
            this.mItemBinding = binding;
        }

        public void bindTo(User user){
            mItemBinding.setUser(user);//将数据设置到布局文件中
            mItemBinding.executePendingBindings();//强行绑定数据

        }

        static MyHolder create(LayoutInflater inflater, ViewGroup parent) {
            UserItemBinding binding =       //获取一个item布局文件的Binding
                    UserItemBinding.inflate(inflater, parent, false);
            return new MyHolder(binding);
        }
    }
}
在布局文件中还支持的表达式
  • 数学表达式:+=*/
  • 字符串拼接:+
  • 逻辑表达式:&& ||
  • 位操作符:^ | &
  • 一元操作法:+-!~
  • 位移操作符:>> << >>>
  • 比较操作符:== > >= < <=
  • instanceof
  • 分组操作符:()
  • 强转、方法调用
  • 字面量:character、String、numeric、null
  • 字段的访问:User.name
  • 数组
  • 三元操作符:? :

以上便是浅浅的总结,希望可以指出不足之处,谢谢。
源码连接:https://github.com/asendiLin/MVVMDemo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值