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&lt;String&gt;" />
    <variable name="map" type="Map&lt;String, String&gt;" />
</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:

  1. DataBinding的基本概念和配置
  2. 布局文件和绑定表达式
  3. 事件处理
  4. 双向数据绑定
  5. BindingAdapter自定义属性
  6. Observable数据
  7. RecyclerView绑定
  8. 最佳实践

DataBinding可以大大减少样板代码,提高开发效率。

最后更新:2026-03-26