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

这边算是对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 使用方法总结(姐姐篇)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345