Android MVVM模式

1、MVVM模式各部分的定义

1.1、MVVM模式分为3个部分:Model、View和ViewModel。

(1)Model :数据层,包含数据实体和对数据实体的操作。

(2)View : 界面层,对应于Activity、XML、View,负责数据显示以及用户交互。

(3)ViewModel : 关联层,将Model和View进行绑定,Model或View更改时,实时刷新对方。

1.2、注意点

(1)View只做和UI相关的工作,不涉及任何业务逻辑、不涉操作数据、不处理数据。UI和数据严格的分开。

(2)ViewModel只做和业务逻辑相关的工作,不涉任何和UI相关的操作、不持有控件引用,不更新UI。

2、MVVM模式图

《Android MVVM模式》 mvvm模式图.png

3、MVVM的优势和劣势

3.1、MVVM的优势

(1)、使得M,V,VM的解耦更加彻底,在mvp模式中,p需要持有v的引用,才能去刷新ui;在mvvm模式中,View和Model使用databingding进行双向绑定,一方改变会直接通知另外一方,使得viewmodel能专注于业务逻辑的处理,而不需要去关心ui刷新。(最大优势,下面两个可忽略。)

(2)、不需要findViewById也不需要butterknife,不需要拿到具体的View去设置数据等,这些都可以用DataBinding完成。

(3)、不会像MVC一样导致Activity中代码量巨大,也不会像MVP一样出现大量的View接口(Presente与View是通过接口进行交互的)。项目结构更加低耦合。

3.2、MVVM的劣势

MVVM的缺点数据绑定使得Bug很难被调试。你看到界面异常了,有可能是你 View 的代码有 Bug,也可能是 Model 的代码有问题。

4、Databinding框架

4.1、Databinding和MVVM的关系

MVVM是一种架构模式,DataBinding是一个实现数据和UI绑定的框架,是实现MVVM模式的工具。

4.2、Databinding常用方法

4.2.1、BindingAdapter注解设置自定义属性

public class ImageHelper {

    /**
     * 1.加载图片,无需手动调用此方法
     * 2.使用@BindingAdapter注解设置自定义属性的名称,imageUrl就是属性的名称,
     * 当ImageView中使用imageUrl属性时,会自动调用loadImage方法,
     *
     * @param imageView ImageView
     * @param url       图片地址
     */
@BindingAdapter({"imageUrl", "placeHolder",“error"})
public static void loadImage(ImageView view, String url, Drawable holderDrawable, Drawable errorDrawable) {
     Glide.with(imageView.getContext())  
                .load(url)  
                .placeholder(holderDrawable)  
                .error(errorDrawable)  
                .into(imageView);
}
}

使用@BindingAdapter注解设置自定义属性的名称,如上所示,imageUrl就是属性的名称,当ImageView中使用imageUrl属性时,会自动调用loadImage方法,参数imageView为当前使用imageUrl属性的ImageView,参数url为图片地址。

xml中使用自定义属性

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <import type="com.zx.databindingdemo.bean.UserBean" />
        <variable
            name="user"
            type="UserBean" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="15dp"
        android:orientation="vertical">

        <!-- 当imageUrl属性存在时,会自动调用ImageHelper的loadImage方法 -->
        <ImageView
            android:layout_width="120dp"
            android:layout_height="120dp"
            android:scaleType="centerCrop"
            app:error="@{user.errorUrl}"
            app:placeHolder="@{user.placeHolder}"
            app:imageUrl="@{user.picUrl}" />
    </LinearLayout>
</layout>   

Activity中设置图片的url

public class BasicActivity extends AppCompatActivity  {
    //用户头像
    private static final String URL_USER_PIC = "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=4138850978,2612460506&fm=200&gp=0.jpg";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityBasicBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_basic);

        UserBean userBean = new UserBean(URL_USER_PIC, "张三", 24);
        binding.setUser(userBean);
    }
}

4.2.1、DataBinding动态更新数据的2种方式
(1)、BaseObservable
这个类也实现了字段变动的通知,在变量的getter上使用 Bindable注解,并通过notifyPropertyChanged通知更新即可。

public class DoubleBindBean extends BaseObservable {

 // 用 @Bindable 标记过 getxxx() 方法会在 BR 中生成一个 entry。 当数据发生变化时需要调用 notifyPropertyChanged(BR.content) 通知系统 BR.content这个 entry 的数据已经发生变化以更新UI。

    private String content; //内容

    public DoubleBindBean(String content) {
        this.content = content;
    }

    @Bindable
    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
        notifyPropertyChanged(BR.content); //通知系统数据源发生变化,刷新UI界面
    }
}

(2)、ObservableFields

如果想要省时,或者数据类的字段很少的话,可以使用 ObservableField 以及它的派生 ObservableBoolean、 ObservableByte ObservableChar、ObservableShort、ObservableInt、ObservableLong、ObservableFloat、ObservableDouble、 ObservableParcelable 等。

public class DoubleBindBean2 {
    //变量需要为public
    public final ObservableField<String> username = new ObservableField<>();
}

Observable Collections
除了支持ObservableField,ObservableBoolean,ObservableInt等基础变量类型以外,当然也支持集合框架拉,比如:ObservableArrayMap,ObservableArrayList。使用和普通的Map、List基本相同

    原文作者:小红军storm
    原文地址: https://www.jianshu.com/p/58023332c74e
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞