当前位置: 首页 > article >正文

Android DataBinding的使用

一、介绍


本文是用来简记DataBinding使用前的配置及一些情况下的使用。

二、环境配置


在项目的要使用DataBinding的module的gradle构建文件里添加如下文件:

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

DataBinding插件将会在你的项目内添加必需提供的以及编译配置依赖。

三、简单使用DataBinding


1、layout文件


DataBinding layout文件与普通布局文件的不同点是:
根标签是 layout ,然后是一个 data 标签和一个ViewGroup标签,此ViewGroup即普通布局的根布局。如下:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="user" type="com.zf.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView 
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"/>
       <TextView 
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.lastName}"/>
   </LinearLayout>
</layout>

data标签中声明了User类并指定了类对象,在当前layout中可以使用该类。
在layout中的使用方式:@{},如上面的:

android:text="@{user.firstName}"


2、数据类


在com.zf包下创建一个User类:

public class User {
   public final String firstName;
   public final String lastName;
   public User(String firstName, String lastName) {
       this.firstName = firstName;
       this.lastName = lastName;
   }
}


3、Binding数据


编译之后会在build\generated\source\apt\debug\项目包名\databinding中生成对应的Binding类。在上述为main_activity.xml,在MainActivity中使用会生成一个MainActivityBinding类,然后调用binding.setUser(user)就可以完成数据的刷新。生成binding的最简单方式是inflating。

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity);
   User user = new User("Test", "User");
   binding.setUser(user);
}


四、layout文件


1、variable


在data中可以使用任意数量的variable元素,每个variable元素会在对应的Binding类中生成对应的set、get方法。如下:

<data>
    <variable
        name="beanHairSideHome"
        type="cn.yanzijia.mine.model.HairSideHomeBean" />

</data>
public abstract void setBeanHairSideHome(@Nullable cn.yanzijia.mine.model.HairSideHomeBean BeanHairSideHome);
@Nullable
public cn.yanzijia.mine.model.HairSideHomeBean getBeanHairSideHome() {
    return mBeanHairSideHome;
}

2、import


可以在data中添加零个或多个import元素,引入的类可以在layout中直接使用。如下:

<data>
<import type="android.view.View" />
<variable
    name="beanHairSideHome"
    type="cn.yanzijia.mine.model.HairSideHomeBean" />
</data>

<cn.yanzijia.commonsdk.widget.CustomImageView
    android:id="@+id/mineHairSideFirstImage"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:foreground="@drawable/mine_foreground_ffffff_8dp"
    android:visibility='@{beanHairSideHome.my_hair.img_list.isEmpty()?View.GONE:View.VISIBLE}' />

当类名有冲突的时候可以使用alias设置别名:

<import type="android.view.View"/>
<import type="com.zf.View" alias="myView"/>

在data中使用import导入的类型可以在variable中使用。

<data>
    <import type="com.zf.User"/>
    <import type="java.util.List"/>
    <variable name="userList" type="List<User>"/>
 </data>

3、自定义Binding类名称


默认情况下,生成的Binding类的名称是布局文件去除下划线、(),所有单词首字母大写(被下划线分割的视为一个单词)。
然后再后面加上Binding。被放置在build\generated\source\apt\debug\项目包名\databinding包下。

自定义Binding类名称:
通过data标签后的class属性来进行重命名,如下:

<data class="MineBinding">
    ...
</data>


更换生成的Binding类所在的包:
直接在刚刚的指定的名称前指定包名就可以了。

<data class="com.zf.MineBinding">
    ...
</data>

4、includes


使用如下:

home.xml

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <import type="android.view.View" />
        <variable
            name="fragment"
            type="cn.yanzijia.poster.ui.fragment.HomeTabFragment" />

        <variable
            name="newOrderLeftTime"
            type="String[]" />

        <variable
            name="newOrderCreateTime"
            type="CharSequence" />

        <variable
            name="onlineInfoBean"
            type="cn.yanzijia.poster.model.HomeOnlineInfoBean.ResultBean" />
    </data>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <include
            layout="@layout/poster_layout_home_xm_new_order"
            android:visibility="@{onlineInfoBean.order_new_num>0?View.VISIBLE:View.GONE}"
            app:bean="@{onlineInfoBean}"
            app:fragment="@{fragment}"
            app:newOrderCreateTime="@{newOrderCreateTime}"
            app:newOrderLeftTime="@{newOrderLeftTime}" />
    </LinearLayout>
</layout>


poster_layout_home_xm_new_order.xml文件:

...
<data>

    <variable
        name="bean"
        type="cn.yanzijia.poster.model.HomeOnlineInfoBean.ResultBean" />
    <import type="android.view.View" />

    <import type="android.text.TextUtils" />

    <variable
        name="fragment"
        type="cn.yanzijia.poster.ui.fragment.HomeTabFragment" />

    <variable
        name="newOrderLeftTime"
        type="String[]" />

    <variable
        name="newOrderCreateTime"
        type="CharSequence" />

</data>
...

注意点:
include中添加的传递项在接收的xml文件中必须一一对应。
名称也必须相同。

5、表达式


?? 符号:如果 ?? 左边的对象不为空则取左边的对象,否则取右边的对象。

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


三元运算符 ?:

android:text="@{user.firstName != null ? user.firstName : user.lastName}"


[] 符号:用来访问常用集合的值。

<data>
    <import type="android.util.SparseArray"/>
    <import type="java.util.Map"/>
    <import type="java.util.List"/>
    <variable name="list" type="List<String>"/>
    <variable name="sparse" type="SparseArray<String>"/>
    <variable name="map" type="Map<String, String>"/>
    <variable name="index" type="int"/>
    <variable name="key" type="String"/>
</data>
…
android:text="@{list[index]}"
…
android:text="@{sparse[index]}"
…
android:text="@{map[key]}"

访问resources资源
正常访问:

android:src="@{@drawable/poster_ic_fab_back_top}"

使用三元表达式:

android:src="@{islarge? @drawable/poster_ic_fab_back_top : @drawable/poster_ic_fab_back_top2}"


五、Data 对象


上述示例中,Data数据显示在UI上,但是改变Data属性UI不会刷新。DataBinding可以通过绑定使数据变化时UI随之刷新。数据变化的通知方式有三种:Observable objects,ObservableField,observable collection:观察对象、观察字段、观察集合。

1、Observable objects


ViewModel类:

public class User extends BaseObservable {
    public String firstName;
    public String lastName;

    public User(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    @Bindable
    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
        notifyPropertyChanged(BR.firstName);
    }

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

    public void setLastName(String lastName) {
        this.lastName = lastName;
        notifyPropertyChanged(BR.lastName);
    }
}

Acivity类中设置及切换数据:

private ActivityMainBinding mBinding;
private User user;
private String[] first = {"张", "周", "李"};
private String[] last = {"倩倩", "花花", "小小"};
private int i = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
    user = new User("李","笑笑");
    mBinding.setUser(user);

}

public void changeData(View view) {
    if (i >= first.length) i = 0;
    user.setFirstName(first[i]);
    user.setLastName(last[i]);
    i++;
}

activity_main.xml文件:

<layout>
    <data>
        <variable
            name="user"
            type="com.example.zf.databindingdome.User"/>
    
    </data>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.firstName+user.lastName}"
            android:textSize="20sp"
            android:textColor="#333333"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_marginTop="20dp"/>
        <Button
            android:onClick="changeData"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Observable objects"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"/>

    </android.support.constraint.ConstraintLayout>
</layout>

在 set 方法里面,使用 notifyPropertyChanged 来通知 UI 刷新,notifyPropertyChanged 只会刷新具体的值,notifyChange 方法则会刷新所有的值。
BR 的域则是通过在 get 方法上加 @Bindable 生成的。

注意:如果在layout文件中使用get方法获取ViewModel中的值,则改变ViewModel中的值的时候不会刷新UI。

2、ObservableField


ViewModel类:

public class UserField {
    public final ObservableField<String> userName=new ObservableField<>();
    public final ObservableField<String> userPassword=new ObservableField<>();
}

直接把属性定义成 ObservableField 类型的,并且修饰符需要是 public final 的。
除了 ObservableField,还可以使用 ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat, ObservableDouble, ObservableParcelable。
访问值得时候,可以使用 get set 方法。

Activity中的处理:

private ActivityMainBinding mBinding;
private UserField userField;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

    userField = new UserField();
    userField.userName.set("张三");
    userField.userPassword.set("123456");
    mBinding.setUserField(userField);

}

public void login(View view) {
    userField.userName.set("李四");
    userField.userPassword.set("098765");
}

activity_main.xml文件:

<layout>
    <data>
        <variable
            name="userField"
            type="com.example.zf.databindingdome.UserField"/>
    </data>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{userField.userName+userField.userPassword}"
            android:textSize="20sp"
            android:textColor="#333333"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_marginTop="50dp"/>

        <Button
            android:onClick="login"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="ObservableField"
            android:layout_marginTop="80dp"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"/>

    </android.support.constraint.ConstraintLayout>
</layout>

3、observable collection

如果使用 Map,List 等保存数据。DataBinding 也提供了 ObservableArrayMap,ObservableArrayList。
修改集合中的值对应UI的值也随之改变。

Activity中的处理:

private ObservableMap<String, Object> objectObservableMap;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

    objectObservableMap = new ObservableArrayMap<>();
    objectObservableMap.put(Keys.name, "王五");
    mBinding.setMap(objectObservableMap);

}
public void collections(View view) {
    objectObservableMap.put(Keys.name,"赵六");
}

activity_main.xml文件:

<layout>
    <data>
        <import type="android.databinding.ObservableMap"/>
        <import type="com.example.zf.databindingdome.Keys"/>
        <variable
            name="map"
            type="ObservableMap&lt;String,Object>"/>
    </data>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{map[Keys.name]}"
            android:textSize="20sp"
            android:textColor="#333333"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_marginTop="70dp"/>
     
        <Button
            android:onClick="collections"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="observable collection"
            android:layout_marginTop="160dp"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"/>

    </android.support.constraint.ConstraintLayout>
</layout>

variable 类型声明的集合要添加泛型,但是泛型不能使用’<'字符。否则会报错:与元素类型 "variable" 相关联的 "type" 属性值不能包含 '<' 字符。
1
如果不使用泛型会报错:

Found data binding errors.
****/ data binding error ****msg:Cannot find the setter for attribute 'android:text' with parameter type V on android.widget.TextView.
file:E:\demo\DataBindingDome\app\src\main\res\layout\activity_main.xml
loc:46:28 - 46:41
****\ data binding error ****

可以使用’<'的转义字符:<其它特殊符号的转义字符:

&(逻辑与)  &amp;
<(小于)    &lt;
>(大于)    &gt;
"(双引号)  &quot;
'(单引号)  &apos;

六、Binding 类的生成


1、获取生成的 Binding 类的几个方法
DataBindingUtil.setContentView(Activity activity,int layoutId)
ActivityMainBinding mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

一般在Activity中使用

DataBindingUtil.inflate(LayoutInflater inflater, int layoutId, ViewGroup parent, boolean attachToParent)

一般用于Fragment或者Adapter中。

DataBindingUtil.bind(View root)
public class QuickDataBindingVH<T extends ViewDataBinding> extends BaseViewHolder {
    public T binding;
    public QuickDataBindingVH(ViewGroup parent, @LayoutRes int itemLayoutRes) {
        super(LayoutInflater.from(parent.getContext()).inflate(itemLayoutRes, parent, false));
    }
    public QuickDataBindingVH(View view) {
        super(view);
        binding=DataBindingUtil.bind(view);
    }
    public T getBinding() {
        return binding;
    }
}

RecyclerView封装的可使用的ViewHolder

2、Binding 的生成


view 的id
layout 中的每个带id的 View 在生成的Binding类中都会生成一个对应的 public final 成员变量。

<TextView
    android:id="@+id/tvUser"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{user.firstName+user.lastName}"
    android:textSize="20sp"
    android:textColor="#333333"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    android:layout_marginTop="20dp"/>

会生成:

@NonNull
public final android.widget.TextView tvUser;

variables
每个variable都会在Binding类中生成对应的访问方法。

<data>
    <variable
        name="user"
        type="com.example.zf.databindingdome.User"/>
    <variable
        name="userField"
        type="com.example.zf.databindingdome.UserField"/>
</data>

会在Binding 类中生成setters和getters

public void setUserField(@Nullable com.example.zf.databindingdome.UserField UserField) {
    this.mUserField = UserField;
    synchronized(this) {
        mDirtyFlags |= 0x10L;
    }
    notifyPropertyChanged(BR.userField);
    super.requestRebind();
}
@Nullable
public com.example.zf.databindingdome.UserField getUserField() {
    return mUserField;
}

public void setUser(@Nullable com.example.zf.databindingdome.User User) {
    updateRegistration(3, User);
    this.mUser = User;
    synchronized(this) {
        mDirtyFlags |= 0x8L;
    }
    notifyPropertyChanged(BR.user);
    super.requestRebind();
}
@Nullable
public com.example.zf.databindingdome.User getUser() {
    return mUser;
}


executePendingBindings()方法
When a variable or observable object changes, the binding is scheduled to change before the next frame. There are times, however, when binding must be executed immediately. To force execution, use the executePendingBindings() method.


http://www.kler.cn/a/327587.html

相关文章:

  • PG-DERN 解读:少样本学习、 双视角编码器、 关系图学习网络
  • Ansible内置模块之known_hosts
  • 脑机接口、嵌入式 AI 、工业级 MR、空间视频和下一代 XR 浏览器丨RTE2024 空间计算和新硬件专场回顾
  • Python 正则表达式使用指南
  • Typescript中的keyof类型操作符详解
  • Redis基础篇
  • pytorch之自动求导
  • 官网:视觉是第一记忆,没有记忆点的官网设计是失败的。
  • 【Ubuntu】安装常用软件包-mysql
  • Meta Llama 3.2发布:小型文本模型与多模态视觉能力,AI的未来已来!
  • CC面试准备
  • 如何从huggingface下载
  • C++杂项
  • 裸金属服务器与虚拟机、物理机区别
  • 基于SpringBoot+Vue+MySQL的美食信息推荐系统
  • 大联大友尚集团推出基于炬芯科技产品的蓝牙音箱方案
  • INTO:Web3世界的“价值引力场”
  • asp.net mvc 常用特性
  • psutil库的使用说明
  • 【线程】线程池
  • 通过ChatGPT 提示词设定60种不同的写作风格
  • LeetCode讲解篇之53. 最大子数组和
  • 【前端安全】js逆向之微信公众号登录密码
  • 使用kaggle命令下载数据集和模型
  • MAGICORE:基于多代理迭代的粗到细精炼框架,提升大语言模型推理质量
  • 普通二叉搜索树的模拟实现【C++】