Android Jetpack之DataBinding

1. 简介

DataBinding 是谷歌官方发布的一个框架,使数据能够单向或双向绑定到 layout 文件中,能够省去我们一直以来的 findViewById() 步骤,大量减少 Activity 内的代码

2. 使用

启用DataBinding

在build.gradle文件Android代码块下加入以下代码,就可以启用DataBinding啦
//启用DataBinding
 dataBinding {
   enabled = true
 }

修改布局文件

在布局文件中,选择跟布局,按下Alt + 回车键,选择 Convert to data binding layout 就自动生成DataBinding布局啦
在这里插入图片描述
我们来看看转换后的布局
在这里插入图片描述
可以看到,转换后我们的跟布局变成了 layout , 中间多了 data 标签,我们的布局文件被移动到下方去啦
其他的都好理解,我们来看看新增的这个 data 标签是干嘛的呢
data 标签就是用来声明在页面中要用到的变量以及变量类型
下面我们来看看怎么使用
首先我们定义一个Model类

public class Account {

    private String accountName;

    private int level;

    ....
}

在页面 data 标签中声明需要使用的变量和类

<data>
    <variable
       name="account"
       type="com.chxip.databinding.Account" />
</data>

然后我们在下方布局定义两个TextView,用于显示账号名称和等级,怎么和上方声明的变量进行绑定呢
答案就是使用 @{变量名},下面我们看具体使用

<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    .....
    <TextView
        android:id="@+id/tv_account_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{account.accountName}" />
	...
    <TextView
        android:id="@+id/tv_account_level"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{account.level}" />
</LinearLayout>

@{account.accountName} 就可以把 accountName 的值设置到TextView 上啦

最后我们修改一下Activity

ActivityMainBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
    Account account=new Account();
    account.setAccountName("chxip6");
    account.setLevel(100);
    binding.setAccount(account);
}

首先我们定义当前ActivityBinding 的变量
然后覆盖setContentView() 为 DataBindingUtil.setContentView() ,这个方法会返回当前ActivityBinding的对象

ActivityMainBinding 这个类为自动生成,如果没有,Clean 一下项目就会出现啦,生成规则为Activity的名称+Binding

然后定义一个Account 对象,赋值账号名称和等级,最后调用binding.setAccount()方法,传入account

我们现在来运行一下看看

我们运行发现报错了,查看错误发现等级是int,但是TextView 不能直接setTex(int ),我们需要修改一下

	   <TextView
	      android:id="@+id/tv_account_level"
	      android:layout_width="wrap_content"
	      android:layout_height="wrap_content"
	      android:text="@{Integer.toString(account.level)}" />

我们需要在赋值的时候,把int 转成String

从这里可以看出,DataBinding 在内部也是使用TextView的setText() 方法赋值的
java.lang.* 包中的类会自动导入进来,可以直接使用

我们现在来运行看看效果
在这里插入图片描述

可以看到,账号名称和等级已经正确的显示到页面上啦

那我们的值改变了后,怎么刷新页面呢?

下面我们就来改变等级看看,添加一个按钮,点击按钮,等级加一

  binding.btnLevelAdd.setOnClickListener(new View.OnClickListener() {
     @Override
     public void onClick(View view) {
           account.setLevel(account.getLevel()+1);
           binding.setAccount(account);
    }
 });

我们这里不用findViewById啦,直接使用binding对象就可以找到这个按钮,设置其点击事件,在点击事件中,我们修改了account的等级,在调用binding.setAccount(),这样就可以改变页面的值啦,我们来看一看运行效果

当然我们也可以直接在布局文件中绑定点击事件,后续我们在介绍这种方式

在这里插入图片描述
我们看到等级的值已经成功改变啦

值改变后,可不可以自定刷新页面呢?

答案是可以的,下面我们来看看怎么在等级改变时,自动刷新页面

我们可以让我们的Model类继承BaseObservable这个类,BaseObservable 提供了 notifyChange() 和 notifyPropertyChanged() 两个方法,前者会刷新所有的值域,后者则只更新对应 BR 的 flag,该 BR 的生成通过注释 @Bindable 生成DataBinding框架会在BR这个生成类中,为name属性生成一个唯一的标识符

首先我们先修改Model类

	//如果是 private 修饰符,则在成员变量的 get 方法上添加 @Bindable 注解
    //只有在需要在单独更新这个属性的时候,才需要加入这个注解
    private String accountName;

    //如果是 public 修饰符,则可以直接在成员变量上方加上 @Bindable 注解
    @Bindable
    public int level;
	...

    public void setLevel(int level) {
        this.level = level;
        //自动更新值
        notifyPropertyChanged(BR.level);
    }

    /**
     * 更新账号和密码
     * @param accountName
     * @param level
     */
    public void setData(String accountName,int level){
        this.accountName = accountName;
        this.level = level;
        notifyChange();
    }

然后我们定义两个按钮,第一个修改等级,第二个修改账号名称和等级

binding.btnLevelAdd.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View view) {
   		//此处只需要调用setLevel方法
        account.setLevel(account.getLevel()+1);
   }
});
binding.btnUpdate.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View view) {
   		//此处调用setData方法
   		account.setData("无敌就是我",1000);
   }
});

我们再来看看效果
在这里插入图片描述
我们可以看到,页面上的值都可以更新啦

这样写还需要每次都调用notifyChange 方法更新,还是没有在数据改变时,自动更新,我们可以使用ObservableField 来实现真正的自动更新
ObservableField 可以理解为官方对 BaseObservable 中字段的注解和刷新等操作的封装,官方原生提供了对基本数据类型的封装,例如 ObservableBoolean、ObservableByte、ObservableChar、ObservableShort、ObservableInt、ObservableLong、ObservableFloat、ObservableDouble 以及 ObservableParcelable ,也可通过 ObservableField 泛型来申明其他类型

如果属性是集合,DataBinding框架也提供了专门的类:
ObservableArrayMap
ObservableArrayList

下面我们来修改一下Modle的代码

	private ObservableField<String> accountName;

    private ObservableInt level;

    public ObservableField<String> getAccountName() {
        if(accountName==null){
            accountName = new ObservableField<>();
        }
        return accountName;
    }

    public void setAccountName(ObservableField<String> accountName) {
        this.accountName = accountName;
    }

    public ObservableInt getLevel() {
        if(level == null ){
            level = new ObservableInt();
        }
        return level;
    }

    public void setLevel(ObservableInt level) {
        this.level = level;
    }

    /**
     * 更新账号和密码
     * @param accountName
     * @param level
     */
    public void setData(String accountName,int level){
         getAccountName().set(accountName);
         getLevel().set(level);
    }

在修改一下点击事件 的代码

	binding.btnLevelAdd.setOnClickListener(new View.OnClickListener() {
       @Override
       public void onClick(View view) {
           account.getLevel().set(account.getLevel().get()+1);
       }
   });
  binding.btnUpdate.setOnClickListener(new View.OnClickListener() {
       @Override
       public void onClick(View view) {
           account.setData("无敌就是我",1000);
       }
  });

这样就可以自动更新数据啦

使用 ObservableField 等 ObservableXXX类,可以让我们省去继承BaseObservable、添加注解,通知DataBinding框架等麻烦,但天下没有免费的午餐,代价就是性能会降低,所以只能在少量属性上这样用,如果大量使用,用户体验可能不太好。

双向绑定

双向绑定的意思即为当数据改变时同时使视图刷新,而视图改变时也可以同时改变数据,双向绑定只是在页面绑定数据的时候,多加一个等号
我们在页面中添加一个EditText,使其双向绑定accountName账号

<EditText
    android:id="@+id/et_account_level"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:hint="请输入账号"
    android:text="@={account.accountName}" />

我们来运行看看效果在这里插入图片描述
我们看到,在输入框中改变账号的值,对应TextView中的值也改变啦

好了,对于DataBinding基本的接收和使用就到这里了,欢迎大家留言交流

有兴趣了解其实现原理的,大家可以看这个

实现原理:DataBinding实现原理探析

参考链接:https://juejin.cn/post/6844903609079971854#heading-5

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值