美文网首页
[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