其它Android知识Android开发

Android: Databinding笔记

2017-02-22  本文已影响236人  thiagooo0

关于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绑定的数据源,如果返回的是一个数字,那就会报这个错误

上一篇 下一篇

猜你喜欢

热点阅读