美文网首页
[AS2.3.3]MVVM模式学习(DataBinding库)

[AS2.3.3]MVVM模式学习(DataBinding库)

作者: 小南2017 | 来源:发表于2018-01-11 15:53 被阅读0次

这边算是对mvvm的学习记录。大部分都来自网上!
先说下Data Binding的利弊

优势

DataBinding 出现以前,我们在实现 UI 界面时,不可避免的编写大量的毫无营养的代码:比如View.findViewById();比如各种更新 View 属性的 setter:setText()setVisibility()setEnabled() 或者setOnClickListener() 等等。
这些“垃圾代码”数量越多,越容易滋生 bug。
使用 DataBinding,我们可以避免书写这些“垃圾代码”。

劣势

使用 Data Binding 会增加编译出的 apk 文件的类数量和方法数量。
新建一个空的工程,统计打开 build.gradle 中 Data Binding 开关前后的 apk 文件中类数量和方法数量,类增加了 120+,方法数增加了 9k+(开启混淆后该数量减少为 3k+)。
如果工程对方法数量很敏感的话,请慎重使用 Data Binding。


1.基本MVVM使用

环境搭配

首先要让Android Studio使用DataBinding库才可以实现mvvm模式
在项目的主app项目Module内加入DataBinding引用

apply plugin: 'com.android.application'

android {
    ......
    dataBinding{
        enabled = true
    }
    ......
}

还有一个注意的就是

  • Android Studio版本在1.3以上
  • gradle的版本要在1.5.0-alpha1以上

基础使用

在说使用之前我们需要将默认的xml布局的最外层加入layout嵌套

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <!--这边设置data数据-->
        ......
    </data>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical">
            <!--这是原来的xml布局-->
            ........
      </LinearLayout>
</layout>

我们创建如下布局


布局
  • 对TextView EditText Button之类的设置文本
    先创建一个mvvmString类
public class mvvmString {
    private String str1;
    private String str2;
    private String str3;

    public mvvmString(String str1, String str2, String str3) {
        this.str1 = str1;
        this.str2 = str2;
        this.str3 = str3;
    }

    public String getStr1() {
        return str1;
    }

    public void setStr1(String str1) {
        this.str1 = str1;
    }

    public String getStr2() {
        return str2;
    }

    public void setStr2(String str2) {
        this.str2 = str2;
    }

    public String getStr3() {
        return str3;
    }

    public void setStr3(String str3) {
        this.str3 = str3;
    }
}

之后我们对xml布局进行设置
首先是data

    <data>
        <variable name="string" type="com.gjn.msdemo.mvvm.mvvmString" />
    </data>

或者

    <data>
        <import type="com.gjn.msdemo.mvvm.mvvmString" />
        <variable name="string" type="mvvmString" />
    </data>

在data内加入variable属性设置名字和类型
之后我们就可以使用了,下面我们对TextView EditText Button分别设置

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{string.str1}" />

        <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:hint="@{string.str2}"
            android:ems="10"
            android:inputType="textPersonName" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{string.str3}" />

之后我们对TestActivity进行绑定数据和设置数据

public class TestActivity extends AppCompatActivity{
    private ActivityTestBinding binding;

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

        binding.setString(new mvvmString("111","222","按钮"));
    }
}

这边提下,在哪个xml下面绑定就会生成相应的Binding
好比这个 R.layout.activity_test 他的生成是按照_进行拼接形成ActivityTestBinding这个类

效果
  • 对ImageView设置图片
    还是创建一个mvvmImage类
public class mvvmImage {
    @BindingAdapter({"image"})
    public static void imageLoader(ImageView imageView, String url){
        Glide.with(imageView.getContext()).load(url).into(imageView);
    }
}

这边用了Glide来加载图片
之后我们在data中加入新的类型

    <data>
        <import type="com.gjn.msdemo.mvvm.mvvmString" />
        <variable name="string" type="mvvmString" />
        <variable name="image" type="String" />
    </data>

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:image="@{image}" />

中间省略了 LinearLayout等布局
使用只需要在binding中加入设置的图片即可

String url = "http://7xi8d6.com1.z0.glb.clouddn.com/20180109085038_4A7atU_rakukoo_9_1_2018_8_50_25_276.jpeg";
binding.setImage(url);
效果2
  • 对Button设置点击事件
    还是先创建一个mvvmClick类
public class mvvmClick {

    public void onClick(View view){
        Toast.makeText(view.getContext(), "点击", Toast.LENGTH_SHORT).show();
    }
}

之后设置data

    <data>
        <import type="com.gjn.msdemo.mvvm.mvvmString" />
        <variable name="string" type="mvvmString" />
        <variable name="image" type="String" />
        <variable name="click" type="com.gjn.msdemo.mvvm.mvvmClick" />
    </data>

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{click.onClick}"
            android:text="@{string.str3}" />

中间省略了 LinearLayout等布局
在Activity中的使用如下

        binding.setClick(new mvvmClick());

点击了按钮就会弹出Toast


效果3

这样就算是绑定了基本的数据了
下面贴下完整的Activity和xml布局的代码

public class TestActivity extends AppCompatActivity{

    private ActivityTestBinding binding;

    private String url = "http://7xi8d6.com1.z0.glb.clouddn.com/" +
            "20180109085038_4A7atU_rakukoo_9_1_2018_8_50_25_276.jpeg";

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

        binding.setString(new mvvmString("111","222","按钮"));

        binding.setImage(url);

        binding.setClick(new mvvmClick());

    }

}
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <import type="com.gjn.msdemo.mvvm.mvvmString" />
        <variable name="string" type="mvvmString" />
        <variable name="image" type="String" />
        <variable name="click" type="com.gjn.msdemo.mvvm.mvvmClick" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:image="@{image}" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{string.str1}" />

        <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:hint="@{string.str2}"
            android:ems="10"
            android:inputType="textPersonName" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{click.onClick}"
            android:text="@{string.str3}" />

    </LinearLayout>
</layout>

2.MVVM进阶使用

  • BaseObservable的使用
    让mvvmStrig继承BaseObservable并改写
public class mvvmString extends BaseObservable{
    private String str1;
    private String str2;
    private String str3;

    public mvvmString(String str1, String str2, String str3) {
        this.str1 = str1;
        this.str2 = str2;
        this.str3 = str3;
    }

    @Bindable
    public String getStr1() {
        return str1;
    }

    public void setStr1(String str1) {
        this.str1 = str1;
        notifyPropertyChanged(com.gjn.msdemo.BR.str1);
    }

    @Bindable
    public String getStr2() {
        return str2;
    }

    public void setStr2(String str2) {
        this.str2 = str2;
        notifyPropertyChanged(com.gjn.msdemo.BR.str2);
    }

    @Bindable
    public String getStr3() {
        return str3;
    }

    public void setStr3(String str3) {
        this.str3 = str3;
        notifyPropertyChanged(com.gjn.msdemo.BR.str3);
    }
}

即对get数据进行Bindabel,设置属性之后调用刷新方法notifyPropertyChanged

这时候修改数据就只要

        mvvmString string = new mvvmString("111","222","按钮");
        binding.setString(string);
        string.setStr1("333");
        string.setStr2("444");
        string.setStr3("按钮2");

就可以修改了。否则如果没有继承BaseObservable的话,修改数据是需要
如下操作

        mvvmString string = new mvvmString("111","222","按钮");
        binding.setString(string);
        string.setStr1("333");
        string.setStr2("444");
        string.setStr3("按钮2");
        binding.setString(string);

就是重新再绑定一次,BaseObservable只是加入了刷新
但是BaseObservable这个方法还是太麻烦了,如果类多了。每个类都写一个M绑定...实在是累人

  • ObservableField的使用
    创建新的mvvmString2
public class mvvmString2 {
    public final ObservableField<String> str1 = new ObservableField<>();
    public final ObservableField<String> str2 = new ObservableField<>();
    public final ObservableField<String> str3 = new ObservableField<>();
}

修改 data使用

    <data>
        <import type="com.gjn.msdemo.mvvm.mvvmString2" />
        <variable name="string" type="mvvmString2" />
        <variable name="image" type="String" />
        <variable name="click" type="com.gjn.msdemo.mvvm.mvvmClick" />
    </data>

使用如下

        mvvmString2 string2 = new mvvmString2();
        binding.setString(string2);
        string2.str1.set("text");
        string2.str2.set("edit");
        string2.str3.set("button");

这样对创建M也方便,并且设置也很快捷

  • BindingAdapter的使用
    上面在修改图片的时候用到了BindingAdapter,这边就在来具体说下BindingAdapter的使用

首先我们先新建一个xml布局
act_test_adapter.xml

<?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>
        <variable name="adapter" type="com.gjn.msdemo.mvvm.mvvmAdapter" />
    </data>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="@{adapter.add}"
            android:text="add" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            app:texts="@{adapter.texts}" />
    </LinearLayout>

</layout>

我们还创建了一个新的mvvmAdapter类

public class mvvmAdapter {
    public ObservableArrayList<String> texts = new ObservableArrayList<>();
    
    public mvvmAdapter(){
        for (int i = 0; i < 5; i++) {
            texts.add("text => " + i);
        }
    }

    @BindingAdapter({"texts"})
    public static void addTextView(LinearLayout linearLayout, ArrayList<String> texts){
        linearLayout.removeAllViews();

        for (String text : texts) {
            TextView textView = new TextView(linearLayout.getContext());
            textView.setText(text);
            linearLayout.addView(textView);
        }

    }

    public void add(View v){
        texts.add("new text");
    }
}

之后修改TestActivity

public class TestActivity extends AppCompatActivity{

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActTestAdapterBinding binding = DataBindingUtil.setContentView(this,R.layout.act_test_adapter);
        binding.setAdapter(new mvvmAdapter());
    }
}

实现效果如下


点击效果

还有一些使用说明

  • 自定义Binding名
    首先我们创建的Bingding都是按照xml生成的,如果我们不希望这样生成可以修改data,在里面加入class属性
    例如
    <data class="NewBinding">
        <variable name="adapter" type="com.gjn.msdemo.mvvm.mvvmAdapter" />
    </data>
  • 别名
    可以再使用导包的时候设置别名,这样有利于区分一些差不多命名的包,就是在import 加入属性alias
    <data class="NewBinding">
        <import type="com.gjn.msdemo.mvvm.mvvmAdapter" alias="testadapter" />
        <variable name="adapter" type="testadapter" />
    </data>
  • 在属性设置的时候要加入包
    如果想设置一些属性
    例如我想设置view的显示属性
    稍微对上面的mvvmAdapter进行修改。这边就贴修改的代码
mvvmAdapter 
public class mvvmAdapter {
    public final ObservableField<Boolean> isView = new ObservableField<>();
}

xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data class="NewBinding">
        <import type="com.gjn.msdemo.mvvm.mvvmAdapter" alias="testadapter" />
        <import type="android.view.View" />
        <variable name="adapter" type="testadapter" />
    </data>
        <!-- 其他布局-->
        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="@{adapter.add}"
            android:visibility="@{adapter.isView ? View.VISIBLE : View.GONE}"
            android:text="add" />
        <!-- 其他布局-->
</layout>

activity
public class TestActivity extends AppCompatActivity{

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

//        ActTestAdapterBinding binding = DataBindingUtil.setContentView(this,R.layout.act_test_adapter);
        NewBinding binding = DataBindingUtil.setContentView(this,R.layout.act_test_adapter);
        mvvmAdapter adapter = new mvvmAdapter();
        binding.setAdapter(adapter);
        adapter.isView.set(false);
    }

}
新效果

资料

【Android】DataBinding库(MVVM设计模式)
安卓 Data Binding 使用方法总结(姐姐篇)

相关文章

网友评论

      本文标题:[AS2.3.3]MVVM模式学习(DataBinding库)

      本文链接:https://www.haomeiwen.com/subject/muoznxtx.html