Databinding踩坑记录

问题1:DataBinding在Kotlin中使用时编译无法通过

要在Kotlin中使用DataBinding需要在app/build.gradle中添加如下代码:

  • Kapt插件:

    1
    apply plugin: 'kotlin-kapt'
  • 打开databinding开关:

    1
    2
    3
    databinding {
    enabled = true
    }
  • kapt databinding compiler:

    1
    kapt 'com.android.databinding:compiler:3.0.0'

最终build.gradle的内容应该与下面相似:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
...//省略其他插件
apply plugin: 'kotlin-kapt'

android {
...//省略其他配置信息
dataBinding {
enabled = true
}
}

dependencies {
//这里的版本号等同于项目的build.gradle文件中的android编译器的版本
//classpath 'com.android.tools.build:gradle:3.0.0'
kapt 'com.android.databinding:compiler:3.0.0'
...
}

问题2:没有生成XML文件对应的Binding类?

生成Binding类的名称默认为XML文件的名称去掉下划线并以驼峰命名法顺序排出所有单词。

例如:activity_main.xml生成的类名叫ActivityMainBinding

问题3:我需要一个变量在代码中产生了值的变化,同步变化到绑定的View上怎么做?

1
2
3
4
5
6
7
8
9
10
class PwdData : BaseObservable() {
...
var minPwdLengthError: String = ""
set(value) {
field = value;notifyPropertyChanged(BR.minPwdLengthError)
}
@Bindable
get
...
}

首先Data class需要继承BaseObservable;其次@Bindable注解需要且仅需要打在get方法上;然后关注变化的语句是notifyPropertyChanged,BR.minPwdLengthError是编译器生成的唯一ID,在给get方法打上注解之后,重新build之后自动生成。

问题4:我要自定义属性绑定怎么办?

AppBinding.kt(Kotlin文件,不是Kotlin类):

1
2
3
4
5
@BindingAdapter("bind:spinnerAdapter")
//android自带属性(如ImageView的src)的绑定请将上方的bind改为android即可
fun setSpinnerAdapter(spinner: Spinner, adapter: BaseAdapter) {
spinner.adapter = adapter
}

其中spinnerAdapter是一个自定义属性(res/values/attrs.xml):

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--这里的自定义属性的格式任意皆可,我统一使用reference-->
<attr name="spinnerAdapter" format="reference" />
...
</resources>

在xml布局文件中调用如下:

1
2
3
4
5
<Spinner
android:id="@+id/spi_fra_pwd_generation_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:spinnerAdapter="@{pwdData.gcSpinnerAdapter}" />

问题5:我该把@BindingAdapter的自定义方法放在哪

很简单,新建一个Kotlin文件即可(不要类),直接在文件里边写“包级”方法。

问题6:自定义绑定方法要多个参数该怎么办?

So Easy!有多少写多少

1
2
3
4
5
6
7
@BindingAdapter("bind:imageUrl", "bind:placeholder")
fun loadImageUrl(imageView: ImageView, url: String, placeholder: Drawable) {
Glide.with(imageView.context).load(url)
.apply(RequestOptions().centerCrop().placeholder(placeholder))
.into(imageView)
println(placeholder)
}

注意,这里是将两个自定义属性绑到同一个方法上,第一个参数必须是写了这几个属性的View。后续几个自定义的参数类型必须一一对应,比如placeholder参数传入的是”@{@drawable/ic_xxx}”,那么方法这里的类型必须是Drawable。

另外,为了应对参数变化情况,你可以同时写好几种情况的方法:

1
2
3
4
5
6
7
8
//三个参数的方法
@BindingAdapter("bind:urlDomain", "bind:imageUrl", "bind:placeholder")
fun loadImageUrl(imageView: ImageView, urlDomain: String, url: String, placeholder: Drawable) {
Glide.with(imageView.context).load(urlDomain + url)
.apply(RequestOptions().centerCrop().placeholder(placeholder))
.into(imageView)
println(placeholder)
}

问题7:我要双向绑定怎么办?

何为双向绑定?

简而言之就是,我在View中修改了值的状态,希望同步变化到绑定的变量上

android自带的属性都几乎已经为你准备好了相应的双向绑定适配器,而一些其他属性或者你自己定义的属性,需要自己写适配器。