databinding的基础和高阶使用

Android开发JetPack-Databinding组件

什么是databinding

我都不想读概念,就一句话,数据源跟UI组件绑定。

为什么要数据源跟ui绑定呢,还不是想开发更简单么。(我们需要先监听数据的变化, 然后再将变化后的数据同步更新到UI上,这样的步骤我们一直在重复,这样的重复性代码我们写了一次又一次。而DataBinding就是为了解决这个问题而存在的,我们只需要将数据绑定到UI元素上,更新数据时UI就会跟着改变,反之亦然,大大节省了我们的代码。

这个我们后续的博客里面会分享,这里涉及到架构的思想就先不细讲。带一句,参照前端的思想。

DataBinding的优势

双向数据绑定
数据发生改变后,DataBinding会自动通知UI刷新页面,不再需要人工绑定最新数据到View上。UI改变后也能同步给数据。

减少模板代码
有了DataBinding,从此不用再写findViewById,setOnClickListener等枯燥生硬的代码,大大提高工作效率。从此ButterKnife靠边站。

释放Activity/Fragment
以前,我们在Activity,Fragment或Presenter中计算数据再绑定到View组件上,导致View层很臃肿,现在这部分工作我们可以直接在xml布局文件中完成。Activity,Fragment让它更加只关注核心业务。

数据绑定空安全
在xml中绑定数据它是空安全的,因为DataBinding在数据绑定上回自动装箱和空判断,所以大大减少了数据绑定带来的空指针问题。

DataBinding的使用

1、在使用DataBinding模块的build.gradle文件中添加下面的配置

// 每个使用dataBinding的模块都应该在build.gradle中添加如下配置
 android {
  ...
  dataBinding {
      enabled = true
  }
}

2、在布局文件中,选中根布局的标签,按住Alt+回车键,点击 Convert to data binding layout,即可转换成DataBinding布局(见下方代码段)、

转换后的布局,最外层变成了layout标签,里面包裹了data标签和常规的布局元素。data元素用来声明在此布局用使用到的变量和变量的类型,以及类引用。

是不是所有属性都能用DataBinding来绑定呢?
当然不是!如果一个属性xxx,在该类中有setXxx方法,我们才能使用DataBinding来绑定。例如android:layout_width, android_layout_height就不能使用DataBinding来绑定数据。而android:paddingLeft, android:textSize都是可以的。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    <data>
        //这里可以使用variable定义多个变量,该变量需要通过外界赋值
        <variable
            name="user"
            type="org.devio.as.main.User" />
        //通过import导入需要用到的类
        <import type="android.view.View"/>
        <import type="org.devio.as.main.UserManager"/>
    </data>
    
    <androidx.constraintlayout.widget.ConstraintLayout>
        <TextView
            android:id="@+id/tvName"
            android:layout_width="200dp"  //不能使用dataBinding动态绑定
            android:text="@{user.name}"  //单向绑定,数据变更自动刷新UI
            android:textSize="@{@dimen/16sp}"//资源引用
            android:text="@{user.name+@string/suffix}"  //字符串的拼接需要引用资源 
            android:text="@{UserManager.getUserName()}" //调用静态方法,类必须先导入
            android:onClick="@{()-> UserManager.login()}"//事件绑定
          />

      <EditText
            //双向绑定数据变更自动更新UI,UI变更了也能自动更新user中name的数据,比单向绑定多个=
           // android:text="@{user.name}"等价于tvName.text = user.name这样就将数据和View相关联了
            android:text="@={user.name}" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

绑定传递数据源
给DataBinding中的User对象赋值

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    //此时可以通过DataBindingUtil来设置Activity的页面布局。
    //此时会返回一个ActivityMainBinding对象。这个是编译时根据xml布局文件中的数据绑定自动生成的实现类。
    ActivityMainBinding  binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
    binding.lifecycleOwner = this
    binding.user = User('张三') //完成数据绑定
    
    //如果是在列表中使用,则可以如下编写 。ActivityMainBinding是根据activity_main布局文件自动生成的
    val binding = ActivityMainBinding.inflate(layoutInflater, null, false)
    binding.user = User('张三') 
}

如何实现数据变化的视图自动更新呢?

DataBinding在xml中数据绑定支持的语法表达式也是非常丰富的,支付在布局文件中使用一下运算符、表达式和关键字:

  • 算术运算符:+ - * / %;
  • 字符串连接运算符:+;
  • 逻辑运算符:&& ||;
  • 二元运算符:& | ^;
  • 一元运算符: + - ! ~;
  • 位移运算符: >> >>> <<;
  • 比较运算符: == > < >= <= (需要被转义);
  • 判断是否是类的实例:instanceof;
  • 分组运算符:();
  • 字面量运算符 - 字符,字符串、数据、null;
  • 类型转换、方法调用;
  • 字段访问;
  • 数组访问: [];
  • 三元运算符:?:;
  • 不支持以下操作:this super new 显示泛型调用。

使用的建议
 

  • 如fragment_layout_mine.xml布局,在编译时会生成FragmentLayoutMineImpl.java实现类,我们可以搜索这种类debug跟进解决问题。

  • 不建议在列表中使用,因为DataBinding数据绑定是延迟一帧的,如果列表中的ItemView的宽高需要计算后才能正确展示,不建议使用DataBinding操作。否则会看到列表ItemView明显的撑开动画,体验不好。
    此处可以使用dataBinding.executePendingBindings()快速渲染布局解决

  • 实体类配合BaseObservable可以友好的解决数据双向绑定的问题。

DataBinding经常出现在MVVM开发模式中,用以减轻Activity/Fragment的压力,可它并不是MVVM必须的一环。

高阶使用 ---> include与viewStub的使用

我们在项目中,有时候需要用到一些公有模块,

公有模块有view 也有数据请求也有逻辑处理。

如果我们不用vm的话,我们就直接初始化公有模块,然后设置初始化参数,调用网络请求,ui设置等。

如果我们用vm的话,那么一样要先把公有的vm写一下,然后对ui部分的更新和一些小逻辑处理,我们就要在xml中处理了。

xml中import的vm可不是固定的。那怎么办呢?

这就引出 include与viewStub的使用

include 和 viewStub 的用法差不多,这里以 include 为例:

例如我们在 Activity 的 xml 布局中添加一个 include 的布局。

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

    <data>
        <variable
            name="testBean"
            type="com.xx.xx.demo.TestBindingBean" /> 
    </data>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/white"
        tools:viewBindingIgnore="true">

      ...

         <include
            layout="@layout/include_databinding_test"
            binding:click="@{click}"
            binding:testBean="@{testBean}" />

    </FrameLayout>

</layout>

我们可以直接把 Activity 的自定义属性 testBean 传入到 include 布局中。

include_databinding_test:

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

    <data>

        <variable
            name="testBean"
            type="com.guadou.kt_demo.demo.demo12_databinding_texing.TestBindingBean" />

        <import
            alias="textUtlis"
            type="android.text.TextUtils" />
    </data>

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

        <TextView
            android:layout_marginTop="15dp"
            android:text="下面是赋值的数据"
            binding:clicks="@{click.testToast}"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{testBean.text1}" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{testBean.text2}" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{testBean.text3}" />

    </LinearLayout>

</layout>

这样在 include 的 xml 中能直接使用自定义属性来显示了。

  • 36
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用双向绑定,需要在项目中引入Data Binding库。在项目的build.gradle文件中添加以下依赖项: ``` android { ... dataBinding { enabled = true } } dependencies { ... implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' } ``` 接下来,我们需要创建ViewModel类。在ViewModel中定义我们需要绑定的变量,并提供getter和setter方法。例如: ``` class MyViewModel : ViewModel() { var name = MutableLiveData<String>() fun setName(newName: String) { name.value = newName } fun getName(): String? { return name.value } } ``` 接下来,我们需要在布局文件中设置双向绑定。例如: ``` <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <import type="android.view.View"/> <variable name="viewModel" type="com.example.MyViewModel"/> </data> <EditText android:id="@+id/editText" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@={viewModel.name}" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Set Name" android:onClick="@{() -> viewModel.setName(editText.text.toString())}" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{viewModel.name}" /> </layout> ``` 在这个布局文件中,我们使用了双向绑定来绑定EditText和TextView中的文本。我们还定义了一个Button来设置ViewModel中的变量。在Button的onClick属性中,我们调用了ViewModel中的setName()方法来设置变量的值。 最后,我们需要在Activity中创建ViewModel实例,并将其绑定到布局文件中。例如: ``` class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main) val viewModel = ViewModelProvider(this).get(MyViewModel::class.java) binding.viewModel = viewModel binding.lifecycleOwner = this } } ``` 在这个例子中,我们使用DataBindingUtil类来绑定布局文件。我们还创建了一个ViewModel实例,并将其绑定到布局文件中。最后,我们设置了lifecycleOwner,以确保数据绑定可以正确地处理生命周期事件。 这样,我们就完成了使用dataBinding和ViewModel进行双向绑定的过程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值