DataBinding #
一、DataBinding概述 #
DataBinding是Jetpack提供的数据绑定框架,可以将布局中的UI组件与数据源绑定,减少样板代码。
1.1 DataBinding的优势 #
- 减少findViewById调用
- 声明式UI更新
- 双向数据绑定
- 减少内存泄漏
1.2 启用DataBinding #
kotlin
android {
buildFeatures {
dataBinding = true
}
}
二、基本使用 #
2.1 布局文件 #
xml
<?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">
<data>
<variable
name="user"
type="com.example.User" />
<variable
name="viewModel"
type="com.example.MainViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.name}" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(user.age)}" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点击"
android:onClick="@{() -> viewModel.onClick()}" />
</LinearLayout>
</layout>
2.2 在Activity中使用 #
kotlin
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
val user = User("张三", 25)
binding.user = user
val viewModel = MainViewModel()
binding.viewModel = viewModel
binding.lifecycleOwner = this
}
}
2.3 在Fragment中使用 #
kotlin
class MainFragment : Fragment() {
private var _binding: FragmentMainBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentMainBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.user = User("张三", 25)
binding.lifecycleOwner = viewLifecycleOwner
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
三、数据绑定表达式 #
3.1 基本表达式 #
xml
<!-- 变量引用 -->
android:text="@{user.name}"
<!-- 算术运算 -->
android:text="@{String.valueOf(user.age + 1)}"
<!-- 字符串连接 -->
android:text="@{`Name: ` + user.name}"
<!-- 三元运算 -->
android:text="@{user.age > 18 ? `成年` : `未成年`}"
<!-- 空安全 -->
android:text="@{user.name ?? `默认名称`}"
3.2 资源引用 #
xml
<!-- 字符串资源 -->
android:text="@{@string/app_name}"
<!-- 带参数的字符串资源 -->
android:text="@{@string/welcome(user.name)}"
<!-- 颜色资源 -->
android:textColor="@{@color/text_color}"
<!-- 尺寸资源 -->
android:textSize="@{@dimen/text_size}"
3.3 集合访问 #
xml
<data>
<import type="java.util.List" />
<import type="java.util.Map" />
<variable name="list" type="List<String>" />
<variable name="map" type="Map<String, String>" />
</data>
<!-- 数组/List访问 -->
android:text="@{list[0]}"
<!-- Map访问 -->
android:text="@{map[`key`]}"
四、事件处理 #
4.1 方法引用 #
kotlin
class MainViewModel : ViewModel() {
fun onButtonClick(view: View) {
// 处理点击
}
}
xml
<Button
android:onClick="@{viewModel::onButtonClick}" />
4.2 监听器绑定 #
kotlin
class MainViewModel : ViewModel() {
fun onUserClick(user: User) {
// 处理点击
}
}
xml
<Button
android:onClick="@{() -> viewModel.onUserClick(user)}" />
4.3 带参数的事件 #
xml
<EditText
android:afterTextChanged="@{viewModel.afterTextChanged}" />
kotlin
class MainViewModel : ViewModel() {
fun afterTextChanged(editable: Editable) {
val text = editable.toString()
}
}
五、双向数据绑定 #
5.1 基本双向绑定 #
xml
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@={viewModel.name}" />
kotlin
class MainViewModel : ViewModel() {
val name = MutableLiveData<String>()
}
5.2 自定义双向绑定 #
kotlin
@BindingAdapter("app:progress")
fun setProgress(view: ProgressBar, progress: Int) {
view.progress = progress
}
@InverseBindingAdapter(attribute = "app:progress", event = "app:progressAttrChanged")
fun getProgress(view: ProgressBar): Int {
return view.progress
}
@BindingAdapter("app:progressAttrChanged")
fun setProgressListener(view: ProgressBar, listener: InverseBindingListener?) {
listener?.let {
view.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
listener.onChange()
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {}
override fun onStopTrackingTouch(seekBar: SeekBar?) {}
})
}
}
六、BindingAdapter #
6.1 自定义属性 #
kotlin
@BindingAdapter("app:imageUrl")
fun loadImage(view: ImageView, url: String?) {
url?.let {
Glide.with(view.context)
.load(it)
.into(view)
}
}
xml
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
app:imageUrl="@{user.avatar}" />
6.2 多参数适配器 #
kotlin
@BindingAdapter(value = ["app:imageUrl", "app:placeholder"], requireAll = false)
fun loadImage(view: ImageView, url: String?, placeholder: Drawable?) {
Glide.with(view.context)
.load(url)
.placeholder(placeholder)
.into(view)
}
xml
<ImageView
app:imageUrl="@{user.avatar}"
app:placeholder="@{@drawable/placeholder}" />
6.3 旧值处理 #
kotlin
@BindingAdapter("app:padding")
fun setPadding(view: View, padding: Float) {
view.setPadding(
padding.toInt(),
padding.toInt(),
padding.toInt(),
padding.toInt()
)
}
七、Observable数据 #
7.1 ObservableField #
kotlin
class User {
val name = ObservableField<String>()
val age = ObservableInt()
}
// 使用
val user = User()
user.name.set("张三")
user.age.set(25)
7.2 ObservableArrayMap #
kotlin
val user = ObservableArrayMap<String, Any>()
user["name"] = "张三"
user["age"] = 25
xml
<TextView
android:text="@{user[`name`]}" />
7.3 ObservableList #
kotlin
val items = ObservableArrayList<String>()
items.add("Item 1")
八、RecyclerView绑定 #
8.1 Item布局 #
xml
<layout>
<data>
<variable name="user" type="com.example.User" />
<variable name="listener" type="com.example.UserClickListener" />
</data>
<LinearLayout>
<TextView
android:text="@{user.name}"
android:onClick="@{() -> listener.onUserClick(user)}" />
</LinearLayout>
</layout>
8.2 ViewHolder #
kotlin
class UserViewHolder(
private val binding: ItemUserBinding
) : RecyclerView.ViewHolder(binding.root) {
fun bind(user: User, listener: UserClickListener) {
binding.user = user
binding.listener = listener
binding.executePendingBindings()
}
}
8.3 Adapter #
kotlin
class UserAdapter(
private val listener: UserClickListener
) : RecyclerView.Adapter<UserViewHolder>() {
private val items = mutableListOf<User>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
val binding = ItemUserBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
return UserViewHolder(binding)
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
holder.bind(items[position], listener)
}
override fun getItemCount() = items.size
fun submitList(newItems: List<User>) {
items.clear()
items.addAll(newItems)
notifyDataSetChanged()
}
}
九、最佳实践 #
9.1 使用LiveData #
kotlin
class MainViewModel : ViewModel() {
private val _name = MutableLiveData<String>()
val name: LiveData<String> = _name
}
xml
<EditText
android:text="@={viewModel.name}" />
kotlin
// 在Activity中设置lifecycleOwner
binding.lifecycleOwner = this
9.2 避免复杂表达式 #
xml
<!-- 不推荐:复杂表达式 -->
android:visibility="@{user.age > 18 && user.isActive ? View.VISIBLE : View.GONE}"
<!-- 推荐:使用BindingAdapter -->
android:app:visibleIfAdult="@{user}"
kotlin
@BindingAdapter("app:visibleIfAdult")
fun setVisibleIfAdult(view: View, user: User?) {
view.visibility = if (user != null && user.age > 18 && user.isActive) {
View.VISIBLE
} else {
View.GONE
}
}
十、总结 #
本章详细介绍了DataBinding:
- DataBinding的基本概念和配置
- 布局文件和绑定表达式
- 事件处理
- 双向数据绑定
- BindingAdapter自定义属性
- Observable数据
- RecyclerView绑定
- 最佳实践
DataBinding可以大大减少样板代码,提高开发效率。
最后更新:2026-03-26