Android: Databinding笔记

作者: thiagooo0 | 来源:发表于2017-02-22 15:30 被阅读236次

    关于databinding

    databinding,即数据绑定。google帮助我们在android上实现mvvm的一个框架。具体的MVVM我理解不深,可以看下这篇文章:Android DataBinding:再见Presenter,你好ViewModel!
    不过从个人感觉上,databinding确实让代码简洁了很多,更新数据的工作也没有这么繁琐了。
    下面是我的学习笔记边学边记。遇到的错误也会记录下来。我没说到的知识点,可以带上梯子到Data Binding Library看。

    配置

    1,首先,Gradle版本需要1.5.0-alpha1以上。

    2,如果Android Studio版本大于1.5,那只需要在对应的module的build.gradle中添加

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

    3,如果Android Studio的版本小于1.5,大于1.3,在project中加入依赖:

    classpath 'com.android.tools.build:gradle:1.2.3'
    classpath 'com.android.databinding:dataBinder:1.0-rc0'
    

    修改对应module的build.gradle

    apply plugin: 'com.android.databinding'
    

    建立数据源

    都说是数据绑定,我们首先需要一个java bean类作为数据源。

    我们可以简单地建一个user类

    public class User {
        private String userName;
        private int age;
    
        public User(String userName, int age){
            setUserName(userName);
            setAge(age);
        }
    
        public String getUserName() {
            return userName;
        }
    
        public void setUserName(String userName) {
            this.userName = userName;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    }
    

    实际上,DataBinding读写数据的时候,是调用get/set方法的。如果不定义变量,只写get/set方法也是可行的。

    public class User {
    
        public String getUserName() {
            return "xiao xin";
        }
    
        public void setUserName(String userName) {
        }
    
        public int getAge() {
            return 33;
        }
    
        public void setAge(int age) {
        }
    }
    
    

    数据更新的时候,view同步更新。

    1.让数据源的类继承BaseObservable类,并且在需要更新的时候调用notifyPropertyChanged()方法。
    代码中的BR是databinding生成的对应数据源的静态变量。和R.id同理。

    private static class User extends BaseObservable {
       private String firstName;
       private String lastName;
       @Bindable
       public String getFirstName() {
           return this.firstName;
       }
       @Bindable
       public String getLastName() {
           return this.lastName;
       }
       public void setFirstName(String firstName) {
           this.firstName = firstName;
           notifyPropertyChanged(BR.firstName);
       }
       public void setLastName(String lastName) {
           this.lastName = lastName;
           notifyPropertyChanged(BR.lastName);
       }
    }
    

    2.可以直接把变量定义为ObservableFields类型的变量,那样每次变量的值发生变化,view也会同步刷新。

    private static class User {
       public final ObservableField<String> firstName =
           new ObservableField<>();
       public final ObservableField<String> lastName =
           new ObservableField<>();
       public final ObservableInt age = new ObservableInt();
    }
    

    一个,特别的,Observable类型的集合 --> ObservableArrayMap
    定义和普通的map差不多

    ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();
    user.put("firstName", "Google");
    user.put("lastName", "Inc.");
    user.put("age", 17);
    

    在layout中使用:

    <data>
        <import type="android.databinding.ObservableMap"/>
        <variable name="user" type="ObservableMap<String, Object>"/>
    </data>
    …
    <TextView
       android:text='@{user["lastName"]}'
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
    <TextView
       android:text='@{String.valueOf(1 + (Integer)user["age"])}'
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
    

    布局

    用了Data Binding的布局文件布局就要变一变了。根元素是一个layout节点。layout节点下面是data节点和原来布局文件的根节点。

    格式如下:

    <layout xmlns:android="http://schemas.android.com/apk/res/android">
        <data>
        </data>
        
        <!--用DataBinding之前的根节点-->
        <LinearLayout>
        ...
        </LinearLayout>
    </layout>
    

    如果要使用user类中的数据,可以这样写

    <layout xmlns:android="http://schemas.android.com/apk/res/android">
    
        <data>
     
            <!--定义了一个User类的变量-->
            <variable
                name="user"
                type="com.test.db.User" />
        </data>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
    
            <!--通过@{user.userName},直接把user里的userName变量的数据写入textview-->
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{user.userName}" />
        </LinearLayout>
    
    </layout>
    

    DataBinding还是挺智能的,如果某些变量没有赋值,会自动赋一个空值。

    相同名字的类

    如果有两个相同名字的类,我们可以这样

    <data>
        <import
            alias="TrueUser"
            type="com.ehang.databindingtest.bean.User" />
    
        <import
            alias="FakeUser"
            type="com.ehang.databindingtest.User" />
            
        <variable
            name="user"
            type="TrueUser" />
    
        <variable
            name="user2"
            type="FakeUser" />
    </data>
    

    然后分别调用user和user2两个变量就好了。

    其他数据类型的变量

    我们还可以定义String,int,map等变量

    <data>
        <import type="java.util.ArrayList" />
    
        <import type="java.util.HashMap" />
        
        <variable
            name="list"
            type="ArrayList" />
    
        <variable
            name="map"
            type="HashMap" />
            
        <variable
            name="str"
            type="String" />
    
        <variable
            name="boo"
            type="boolean" />
    
        <variable
            name="num"
            type="int" />
    </data>
    

    定义好的变量可以在实际的布局中使用了。

    运算符

    Data Binding还支持大多数的运算符。加减乘除,字符合并,逻辑云算法,二元三元等等。
    下面是一个三元元算符的例子。

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text='@{boo?"true": "false"}'/>
    

    数据绑定

    需要在activity中对数据进行绑定。即把数据源和布局关联起来。

    public class MainActivity extends AppCompatActivity {
    
        private User mUser;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //注意,这里已经没有setContentView()方法了。
            ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
    
            mUser = new User("xiao xin", 33);
            binding.setUser(mUser);
        }
    }
    

    至此,就完成了一个简单的DataBinding了。

    动态添加view时,使用databinding

    每一个使用了databinding的布局,都会自动生成一个ViewDatabinding的子类。在例子中,布局R.layout.layout3使用了databinding,从而生成了Layout3Binding类。我们可以通过这个类的 bind(布局实例) 方法来进行数据绑定。

     RelativeLayout.LayoutParams relativeLayoutParams = new RelativeLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
    
        ViewGroup layout1 = (ViewGroup) LayoutInflater.from(this).inflate(R.layout.layout3, null);
        
        rootLayout.addView(layout1, relativeLayoutParams);
        
        Layout3Binding binding1 = Layout3Binding.bind(layout1);
    
        binding1.setData(data);
    

    替换字符

    在string.xml中

        <string name="util">%1$s千克 %2$s米</string>
    

    其中有两个替换字符。

    布局文件中

    android:text="@{String.format(@string/util,model.weight,`123`)}"
    

    util中的字符串中的替换字符分别替换成model.height和123。显示的结果会是“weight的值 千克 123米”

    如果只有一个替换字符时,用

        <string name="util">%s米</string>
    

    include

    给include进来的布局绑定数据,可以这样:

    <include layout="@layout/name"
        bind:user = "@{user}"/>
    

    某个布局用了databinding,这个布局include的所有布局都要用databinding

    include进来的是一个databindiing布局,并不能拿来做动画操作。比如布局a中include了布局b,对b做动画,不能直接使用databinding.b,要用databinding.b.b布局的父布局。

    import

    有些时候我们需要用到其他工具类的静态方法,或者直接拿一个bean的单例来做数据绑定,我们需要先import一下。

    同样是在data标签里面:

     <import type="com.ehang.communication.ViewModel.HudInfoViewModel"/>
    

    然后就可以使用了

     android:text="@{HudInfoViewModel.getInstance().altitude}"
    

    databinding类不存在的错误

    databinding绑定的数据源,如果返回的是一个数字,那就会报这个错误

    相关文章

      网友评论

        本文标题:Android: Databinding笔记

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