DataBinding - 数据绑定
源:数据绑定库
使用声明性格式将布局中的界面组件绑定到应用中的数据源。允许开发者将 UI 组件直接绑定到应用的数据源。这种方式可以减少样板代码,提高代码的可读性和可维护性。通过 Data Binding,开发者可以实现双向数据绑定,使得数据和 UI 的变化能够自动同步。
优点
- 减少样板代码:通过 XML 布局文件直接绑定数据,减少了在 Activity 或 Fragment 中的代码量。
- 提高可维护性:UI 组件和数据逻辑分离,使得代码结构更加清晰。
- 支持双向数据绑定:数据变化时自动更新 UI,UI 变化时也能更新数据模型。
缺点
DataBing虽然带来了很多方便,但是在实际使用中,有时体验却不是那么好
"代码显得很杂乱"。虽然它减少了很多样板代码,但是它需要修改每个
.xml布局(xml布局根节点都要改成<layout></layout>)结构, 在xml里面加了很多绑定代码,导致整个界面看起来很乱。由于需要绑定适配器,Java/Kotlin代码中也需要额外添加很多注解,所以随着功能注解的不断添加,代码也有可能会更难维护
"一些奇怪的编译问题"。DataBinding会使用注解生成很多额外的代码,在编译运行时可能会由于缓存等因素,导致代码或中经常一堆爆红,需要经常clean项目才行
所以,一般情况下还是建议尽量使用 ViewBinding
⭐ 注意
在许多情况下,视图绑定可提供与数据绑定相同的优势,因为它的实现更简单、性能更高。 如果您主要使用数据绑定来取代 findViewById() 调用,请考虑改用视图绑定。
开始使用
数据绑定库与 Android Gradle 插件捆绑在一起。您无需声明对此库的依赖项,但必须启用它。
如需启用数据绑定,请在模块的 build.gradle 文件中将 dataBinding 构建选项设置为 true,如下所示:
android {
buildFeatures {
dataBinding = true
}
}基本数据绑定
传统方式
在传统的 Android 开发中,您通常需要在 Activity 或 Fragment 中使用 findViewById() 方法来查找视图并设置其属性。 例如:
<TextView
android:id="@+id/sample_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>class MainActivity : AppCompatActivity() {
private val viewModel: UserViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textView: TextView = findViewById(R.id.sample_text)
textView.text = viewModel.userName
}
}数据绑定方式
使用数据绑定库后,您可以直接在布局文件中使用绑定表达式来设置视图的属性。
先修改布局根目录结构,加上<layout></layout>(可以将鼠标放到布局文件的第一行选择Convert to data binding layout 自动转换。即可将布局文件改造成DataBinding 格式。DataBinding中xml根布局都要是这这个,后续不再额外描述)
然后修改 TextView,添加 android:text="@{viewModel.userName}" , 这样便会将 viewModel.userName 的数据绑定到了 sample_text Text:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewmodel"
type="com.myapp.data.ViewModel"/>
</data>
<TextView
android:id="@+id/sample_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewModel.userName}"/>
</layout>class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val viewModel: UserViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.viewModel = viewModel
binding.lifecycleOwner = this // 使 LiveData 能够自动更新 UI
}
}绑定表达式
传统方式
在传统方式中,您需要在 Activity 中手动设置每个视图的属性:
// 传统方式
val textView: TextView = findViewById(R.id.sample_text)
textView.text = viewModel.userName
val button: Button = findViewById(R.id.button)
button.setOnClickListener {
viewModel.onButtonClick()
}数据绑定方式
使用数据绑定库,您可以在布局文件中直接绑定视图和数据:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="com.myapp.data.UserViewModel"/>
</data>
<ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/sample_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewModel.userName}"/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click Me"
android:onClick="@{() -> viewModel.onButtonClick()}"/>
</ConstraintLayout>
</layout>绑定可观察的数据对象
在 ViewModel 中,您可以使用 LiveData:
class UserViewModel : ViewModel() {
val userName = MutableLiveData<String>()
init {
userName.value = "Alice"
}
fun onButtonClick() {
userName.value = "Bob"
}
}传统方式
在传统方式中,您需要手动监听数据的变化并更新 UI,当数据源发生变化时:
// 传统方式
viewModel.userName.observe(this, Observer { newName ->
textView.text = newName
})数据绑定方式
使用数据绑定库,您可以直接在布局中绑定可观察的数据对象,UI 会自动更新:
<TextView
android:id="@+id/sample_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewModel.userName}"/>绑定适配器
传统方式
在传统方式中,您需要手动设置视图的属性:
// 传统方式
button.setOnClickListener {
if (viewModel.isButtonVisible) {
button.visibility = View.VISIBLE
} else {
button.visibility = View.GONE
}
}数据绑定方式
绑定适配器允许您为自定义属性创建自定义逻辑。
对于每个布局表达式,都有一个绑定适配器,可进行框架调用以设置相应的属性或监听器。
例如,绑定适配器可以负责调用 setText() 方法来设置文本属性,或调用 setOnClickListener() 方法将监听器添加到点击事件。 您可以在 android.databinding.adapters 软件包中使用最常见的绑定适配器,您还可以创建自定义适配器,如以下示例所示:
@BindingAdapter("app:goneUnless")
fun goneUnless(view: View, visible: Boolean) {
view.visibility = if (visible) View.VISIBLE else View.GONE
}在布局文件中使用自定义适配器:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:goneUnless="@{viewModel.isButtonVisible}"/>双向数据绑定
传统方式
在传统方式中,数据更改需要手动更新UI,UI变化(比如输入框输入数据)需要手动监听并更改数据:
editText.text = viewModel.userName
editText.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
viewModel.userName = s.toString()
}
})数据绑定方式
数据绑定库支持双向数据绑定,允许 UI 和数据模型之间的双向同步。例如,您可以将 EditText 的文本与 ViewModel 中的属性绑定:
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@={viewModel.userName}"/>其他资源
如需详细了解数据绑定,请参阅以下资源(可能需要代理):