欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

android:DataBinding使用小结(一)

程序员文章站 2022-05-14 23:46:39
...

一、初步使用DataBinding

  • 引入DataBinding

    在你的app下的build.gradle中添加对DataBinding的支持
    
android {
    ...
    //第一步:引入dataBinding
    dataBinding {
        enabled = true
    }

}
  • 更改你的xml布局,对dataBinding的支持
<?xml version="1.0" encoding="utf-8"?>
<!--
第二步:在布局中跟节点添加layout
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="tsou.cn.databinding.MainActivity">

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="输入 Frist Name" />

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="输入 Last Name" />

        <TextView
            android:id="@+id/first_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/last_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>
</layout>

  • 在MainActivity中使用dataBinding绑定你的xml布局,并代替findviewbyid

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        User user = new User();
        user.setFristName("huang");
        user.setLastName("xiaoguo");
        //    第三步:使用  ActivityMainBinding
        /**
         * Android studio会根据layout文件自动生成一个默认的Binding类,
         * 类名是根据layout文件名生成的,
         * 并有"Binding"后缀结束。
         * 例如:activity_main.xml生成的Binding类为ActivityMainBinding
         *
         * 如果ActivityMainBinding,无法找到,可以先编译一下项目
         */
        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        /**
         * 解决问题之:findviewbyId
         */
        binding.firstName.setText(user.getFristName());
        binding.lastName.setText(user.getLastName());

    }

二、DataBinding 绑定UI (setVariable、setXXX)

  • 在xml中添加data数据绑定标签
<?xml version="1.0" encoding="utf-8"?>
<!--
第二步:在布局中跟节点添加layout
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <!--
    第四步:xml数据绑定,name表示数据对象名称
    type:表示包名
    -->
    <data>
        <variable
            name="user"
            type="tsou.cn.databinding.bean.User"/>
    </data>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="tsou.cn.databinding.MainActivity">

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="输入 Frist Name" />

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="输入 Last Name" />

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

        <TextView
            android:text="@{user.lastName}"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>
</layout>

  • 将activity中的数据绑定到xml中

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        User user = new User();
        user.setFristName("huang");
        user.setLastName("xiaoguo");
        //    第三步:使用  ActivityMainBinding
        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        /**
         * 将数据绑定到xml
         */
        //  方法一:(常用)
        //binding.setUser(user);
        //方法二:
        binding.setVariable(BR.user,user);

    }
}
  • 其他引入数据姿势

    如果用户类型要多处用到,也可以直接将之后导入进来,
    这样就不用每次都指明整个包名路径了,
    而java.lang.*包中的类会被自动导入,所以可以直接使用
    
<data>
        <import type="tsou.cn.databinding.bean.User"/>
        <variable
            name="user"
            type="User"/>
    </data>
如果存在进口的类名相同的情况,可以使用别名指定别名
<data>
        <import type="tsou.cn.databinding.bean.User" />
        <import
            alias="TwoUser"
            type="tsou.cn.databinding.bean2.User" />
        <variable
            name="user"
            type="User" />
        <variable
            name="twoser"
            type="TwoUser" />
    </data>

三、事件绑定

  • 创建Presenter类
 public class Presenter{
        //普通方法绑定
        public void onTextChanged( CharSequence s,int start,int before,int color){
            user.setFristName(s.toString());
            binding.setUser(user);
        }
        //普通方法绑定
        public void onClick(View view){
            Toast.makeText(MainActivity.this.getApplicationContext(),"点击了",Toast.LENGTH_LONG).show();
        }
        //监听器绑定,可以返回数据
        public void onClickListenerBinding(User user){
            Toast.makeText(MainActivity.this.getApplicationContext(),user.getLastName(),Toast.LENGTH_LONG).show();
        }
    }
  • 在xml中传入presenter并进行绑定
<?xml version="1.0" encoding="utf-8"?><!--
第二步:在布局中跟节点添加layout
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <!--
        第四步:xml数据绑定,name表示数据对象名称
        type:表示包名
         -->
        <variable
            name="user"
            type="tsou.cn.databinding.bean.User" />
        <!--
          第五步:事件绑定
          name:类名
          type:表示包名
        -->
        <variable
            name="presenter"
            type="tsou.cn.databinding.MainActivity.Presenter" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="tsou.cn.databinding.MainActivity">
        <!--
          建议使用
         android:onTextChanged="@{presenter::onTextChanged}"
         可以将方法的绑定和普通函数的调用或数据绑定,区分开
        -->
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="输入 Frist Name"
            android:onTextChanged="@{presenter.onTextChanged}" />

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="输入 Last Name" />

         <!--
         普通方法绑定
          建议使用
          android:onClick="@{presenter::onClick}"
         可以将方法的绑定和普通函数的调用或数据绑定,区分开
        -->
        <TextView
            android:layout_gravity="center"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{presenter.onClick}"
            android:text="@{user.fristName}" />
        <!--
            监听器绑定,可以返回数据
        -->
        <TextView
            android:layout_gravity="center"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{()->presenter.onClickListenerBinding(user)}"
            android:text="@{user.lastName}" />
    </LinearLayout>
</layout>

  • acticity中绑定Presenter对象
binding.setPresenter(new Presenter());
  • 效果如下:

android:DataBinding使用小结(一)

四、xml中对表达式的支持

支持的运算符:

  • 数学运算符: + - / * %
  • 字符串拼接: +
  • 逻辑运算符: && ||
  • 二进制: & | ^
  • 一元运算符: +
  • 位运算符: >> >>> <<
  • 比较: == > < >= <=
  • instanceof
  • ()
  • 数据类型: character, String, numeric, null
  • 类型转换(ClassCast)
  • 方法回调(Method calls)
  • 数据属性
  • 数组:[]
  • 三元操作符:?

例如:

android:text="@{String.valueOf(index + 1)}"
android:visibility="@{age < 13 ? View.GONE : View.VISIBLE}"
android:background="@{true ? @color/colorAccent : @color/colorPrimary}"        
android:transitionName='@{"image_" + id}'

一些在java中常用而DataBinding xml中不支持的:

  • this
  • super
  • new
  • 泛型

空合并运算符

android:text="@{user.displayName ?? user.lastName}"

等价于

android:text="@{user.displayName != null ? user.displayName : user.lastName}"
  • view的显示和隐藏

在xml data节点下引入view

<data>

        <import type="android.view.View" />

    </data>

view的显示和隐藏

 <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="是否显示"
            android:textColor="@color/colorAccent"
            android:textSize="24sp"
            android:visibility="@{user.isShow ? View.VISIBLE:View.GONE }" />

五、include的使用

  • 创建include布局
<?xml version="1.0" encoding="utf-8"?><!--
在布局中跟节点添加layout
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <!--
        xml数据绑定,name表示数据对象名称
        type:表示包名
         -->
        <variable
            name="user"
            type="tsou.cn.databinding.bean.User" />
    </data>

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

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="@{user.fristName}" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="@{user.lastName}" />

    </LinearLayout>
</layout>

  • 使用include布局并传递数据
<include
         layout="@layout/include_layout"
         bind:user="@{user}" />
  • 效果如下
    android:DataBinding使用小结(一)

六、ViewStub使用

  • ViewStub布局
<?xml version="1.0" encoding="utf-8"?><!--
在布局中跟节点添加layout
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <!--
        xml数据绑定,name表示数据对象名称
        type:表示包名
         -->
        <variable
            name="user"
            type="tsou.cn.databinding.bean.User" />
    </data>

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

        <ImageView
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_gravity="center"
            android:src="@mipmap/ic_launcher_round" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.imageId}" />
    </LinearLayout>
</layout>
  • 调用ViewStub
 <ViewStub
            android:id="@+id/view_stub"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout="@layout/viewstub"
            bind:user="@{user}" />
  • 加载viewStub
 //使用viewStub
   binding.viewStub.getViewStub().inflate();

七、BaseObservable数据更新监听使用

  • 将javaBean继承BaseObservable
package tsou.cn.databinding.bean;

import android.databinding.BaseObservable;
import android.databinding.Bindable;

import tsou.cn.databinding.BR;


/**
 * Created by Administrator on 2018/5/25 0025.
 */

//BaseObservable数据自动更新的使用

public class User extends BaseObservable {
    private String fristName;
    private String lastName;
    private String imageUrl;
    private boolean isShow;

    @Bindable
    public boolean getIsShow() {
        return isShow;
    }

    public void setIsShow(boolean show) {
        isShow = show;
        notifyPropertyChanged(BR.isShow);
    }

    @Bindable
    public String getImageUrl() {
        return imageUrl;
    }

    public void setImageUrl(String imageUrl) {
        this.imageUrl = imageUrl;
        notifyPropertyChanged(BR.imageUrl);
    }

    @Bindable
    public String getFristName() {
        return fristName;
    }

    public void setFristName(String fristName) {
        this.fristName = fristName;
        notifyPropertyChanged(BR.fristName);
    }

    @Bindable
    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
        notifyPropertyChanged(BR.lastName);
    }
}
注意:
1、首先当前类继承BaseObservable 

2、对于get方法添加@Bindable注解

3、引入BR.lastName等报错时,需要对项目先进行一下修复
  • 布局中进行监听
<EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="输入 Frist Name"
            android:onTextChanged="@{presenter::onTextChanged}" />
  • 调用方法
 public class Presenter {
        //普通方法绑定
        public void onTextChanged(CharSequence s, int start, int before, int color) {
            user.setFristName(s.toString());
            //此时不需要再次手动进行更新数据对象了
//            binding.setUser(user);
        }
    }

八、ObservableField数据监听的使用

ObservableField是为了解决一个数据类中不需要所有的数据都进行监听时代替BaseObservable,让类当前类不需要继承BaseObservable也不需要重新notifyPropertyChanged方法
  • 在数据类中
    /**
     * 在单个或者比较少的数据需要监听时使用ObservableField
     * (ObservableBoolean,ObservableChar,ObservableInt,ObservableParcelable.....)
     */
    private ObservableField<Boolean> isShow = new ObservableField<>();

    public ObservableField<Boolean> getIsShow() {
        return isShow;
    }

    public void setIsShow(boolean show) {
        /**
         * 如果是Observable*类型设置数据需要使用set
         */
        this.isShow.set(show);
    }
  • 布局中使用
<TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="是否显示"
            android:textColor="@color/colorAccent"
            android:textSize="24sp"
            android:visibility="@{user.isShow ? View.VISIBLE:View.GONE }" />
  • 更新数据
 public class Presenter {
        //普通方法绑定
        public void onTextChanged(CharSequence s, int start, int before, int color) {
            user.setFristName(s.toString());
            //这里直接更改数据就好
            user.setIsShow(!user.getIsShow().get());
//            binding.setUser(user);
        } 
    }

九、ObservableArrayList和ObservableArrayMap的使用

  • 在数据类中
  private ObservableArrayList<String> nums;
    private ObservableArrayMap<String,String> maps;
    public ObservableArrayList<String> getNums() {
        return nums;
    }
    public void setNums(ObservableArrayList<String> nums) {
        this.nums=nums;
    }

    public ObservableArrayMap<String, String> getMaps() {
        return maps;
    }

    public void setMaps(ObservableArrayMap<String, String> maps) {
        this.maps = maps;
    }
  • 布局中使用
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="@{user.nums[0]}" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text='@{user.maps["name"]}' />
  • 添加数据

全局集合对象

private ObservableArrayList<String> nums = new ObservableArrayList<>();
    private ObservableArrayMap<String, String> maps = new ObservableArrayMap<>();

在绑定数据之前添加集合对象

 //ObservableArrayList和ObservableArrayMap的使用:添加对象
        user.setNums(nums);
        user.setMaps(maps);

        /**
         * 将数据绑定到xml
         */
        //  方法一:
        //binding.setUser(user);
        //方法二:
        binding.setVariable(BR.user, user);

更改数据

  nums.add("我是ObservableArrayList");
  maps.put("name", "我是ObservableArrayMap");

十、BindingAdapter的使用

  • 使用BindingAdapter构建图片加载方法

/**
 * Created by Administrator on 2018/5/30 0030.
 */

public class ImageUtil {
    @BindingAdapter({"url"})
    public static void loadImage(ImageView view, String url) {

        Glide.with(UIUtils.getContext()).load(url).into(view);
    }
}
  • xml文件绑定数据
<?xml version="1.0" encoding="utf-8"?><!--
在布局中跟节点添加layout
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:bind="http://schemas.android.com/apk/res-auto">

    <data>
        <!--
        xml数据绑定,name表示数据对象名称
        type:表示包名
         -->
        <variable
            name="user"
            type="tsou.cn.databinding.bean.User" />
    </data>

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

        <!--
        这里的bind:url="@{user.imageUrl}"即为调用 @BindingAdapter({"url"}绑定的数据
        -->
        <ImageView
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_gravity="center"
            bind:url="@{user.imageUrl}"
            android:src="@mipmap/ic_launcher_round" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.imageUrl}" />
    </LinearLayout>
</layout>

  • 添加Url数据
user.setImageUrl("https://unsplash.it/200/200?random&10");

  • BindingAdapter更加强大的一点是可以覆盖Android原先的控件属性。例如,可以设定每一个TextView的文本都要加上后缀:“ - 追加的数据”

    注意:这里追加数据的TextView必须使用数据绑定来填充数据,否则无效
    
 @BindingAdapter("android:text")
    public static void setText(TextView view, String text) {
        view.setText(text + "-追加的数据");
    }

android:DataBinding使用小结(一)

十一、BindingConversion使用

dataBinding还支持数据进行转换,或者进行类型转换。

与BindingAdapter类似,以下方法会将布局文件中所有以@{String}方式引用到的String类型变量加上后缀-conversionString

    @BindingConversion
    public static String conversionString(String text) {
        return text + "-conversionString";
    }
<TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text='@{"xxx"}'
            android:textAllCaps="false"/>

android:DataBinding使用小结(一)

可以看到,对于TextView来说,BindingAdapter和BindingConversion同时生效了,而BindingConversion的优先级要高些。此外,BindingConversion也可以用于转换属性值的类型。

看以下布局,此处在向background和textColor两个属性赋值时,直接就使用了字符串,按正常情况来说这自然是会报错的,但有了BindingConversion后就可以自动将字符串类型的值转为的需要Drawable状语从句:Color了

<TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background='@{"红色"}'
            android:padding="20dp"
            android:text="红色背景蓝色字"
            android:textColor='@{"蓝色"}'/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:background='@{"蓝色"}'
            android:padding="20dp"
            android:text="蓝色背景红色字"
            android:textColor='@{"红色"}'/>
@BindingConversion
    public static Drawable convertStringToDrawable(String str) {
        if (str.equals("红色")) {
            return new ColorDrawable(Color.parseColor("#FF4081"));
        }
        if (str.equals("蓝色")) {
            return new ColorDrawable(Color.parseColor("#3F51B5"));
        }
        return new ColorDrawable(Color.parseColor("#344567"));
    }

    @BindingConversion
    public static int convertStringToColor(String str) {
        if (str.equals("红色")) {
            return Color.parseColor("#FF4081");
        }
        if (str.equals("蓝色")) {
            return Color.parseColor("#3F51B5");
        }
        return Color.parseColor("#344567");
    }

android:DataBinding使用小结(一)

十二、Array、List、Set、Map …

dataBinding也支持在布局文件中使用数组,Lsit,Set和Map,且在布局文件中都可以通过list[index]形式来获取元素。

而为了和变量标签的尖括号区分开,在声明Lsit 之类的数据类型时,需要使用尖括号的转义字符。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <import type="java.util.List" />
        <import type="java.util.Map" />
        <import type="java.util.Set" />
        <import type="android.util.SparseArray" />
        <variable
            name="array"
            type="String[]" />
        <variable
            name="list"
            type="List&lt;String&gt;" />
        <variable
            name="map"
            type="Map&lt;String, String&gt;" />
        <variable
            name="set"
            type="Set&lt;String&gt;" />
        <variable
            name="sparse"
            type="SparseArray&lt;String&gt;" />
        <variable
            name="index"
            type="int" />
        <variable
            name="key"
            type="String" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".Main7Activity">

        <TextView
            ···
            android:text="@{array[1]}" />
        <TextView
            ···
            android:text="@{sparse[index]}" />
        <TextView
            ···
            android:text="@{list[index]}" />
        <TextView
            ···
            android:text="@{map[key]}" />
        <TextView
            ···
            android:text='@{map["leavesC"]}' />
        <TextView
            ···
            android:text='@{set.contains("xxx")?"xxx":key}' />
    </LinearLayout>
</layout>

十三、资源引用

dataBinding支持对尺寸和字符串这类资源的访问

  • dimens.xml
  <dimen name="paddingBig">190dp</dimen>
    <dimen name="paddingSmall">150dp</dimen>
  • strings.xml
  <string name="format">%s is %s</string>
  <data>
        <variable
            name="flag"
            type="boolean" />
    </data>       
    <Button
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:paddingLeft="@{flag ? @dimen/paddingBig:@dimen/paddingSmall}"
         android:text='@{@string/format("leavesC", "Ye")}'
         android:textAllCaps="false" />

其他注意知识点

  • 默认数据

    由于@{userInfo.name}在布局文件中并没有明确的值,
    所以在预览视图中什么都不会显示,
    不便于观察文本的大小和字体颜色等属性,
    此时可以为之设定默认值(文本内容或者是字体大小等属性都适用),
    默认值将只在预览视图中显示,且默认值不能包含引号

android:text="@{user.fristName,default=这是默认数据}"
  • 自定义实例名称

    每个数据绑定布局文件都会生成一个绑定类,
    ViewDataBinding的实例名是根据布局文件名来生成,
    将之改为首字母大写的驼峰命名法来命名,
    并省略布局文件名包含的下划线。
    控件的获取方式类似,但首字母小写。
    也可以通过如下方式自定义ViewDataBinding的实例名
    
<data class="CustomBinding">

</data>

Demo地址:https://download.csdn.net/download/huangxiaoguo1/10454497

相关标签: android DataBinding