功能需求
显示用户的姓名、年龄、身份(学生 / 上班族)
点击按钮切换用户信息
一、传统方式实现
1. 布局文件(activity_main.xml)
XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"/>
<TextView
android:id="@+id/tvAge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"/>
<TextView
android:id="@+id/tvIdentity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"/>
<Button
android:id="@+id/btnChange"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="切换用户"
android:layout_marginTop="16dp"/>
</LinearLayout>
2. Activity 代码(MainActivity.kt)
Kotlin
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
class MainActivity : AppCompatActivity() {
// 声明所有需要操作的控件
private lateinit var tvName: TextView
private lateinit var tvAge: TextView
private lateinit var tvIdentity: TextView
private lateinit var btnChange: Button
// 数据
private var currentUser = User("张三", 20, true)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 1. 手动绑定所有控件(最繁琐的步骤)
initViews()
// 2. 手动更新UI
updateUI()
// 3. 手动设置点击事件
btnChange.setOnClickListener {
// 切换数据
currentUser = if (currentUser.name == "张三") {
User("李四", 25, false)
} else {
User("张三", 20, true)
}
// 手动更新UI
updateUI()
}
}
// 初始化所有控件(findViewById重复劳动)
private fun initViews() {
tvName = findViewById(R.id.tvName)
tvAge = findViewById(R.id.tvAge)
tvIdentity = findViewById(R.id.tvIdentity)
btnChange = findViewById(R.id.btnChange)
}
// 手动更新所有控件内容
private fun updateUI() {
tvName.text = currentUser.name
tvAge.text = "年龄:${currentUser.age}"
tvIdentity.text = if (currentUser.isStudent) "学生" else "上班族"
}
// 数据类
data class User(
val name: String,
val age: Int,
val isStudent: Boolean
)
}
二、Data Binding 方式实现
1. 布局文件(activity_main.xml)
XML
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="user"
type="com.example.databindingdemo.MainActivity.User" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<!-- 直接绑定数据,无需id -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.name}" <!-- 数据绑定 -->
android:textSize="18sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{`年龄:` + user.age}" <!-- 表达式拼接 -->
android:layout_marginTop="8dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.isStudent ? `学生` : `上班族`}" <!-- 条件判断 -->
android:layout_marginTop="8dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="切换用户"
android:layout_marginTop="16dp"
android:onClick="@{() -> user.change()}" <!-- 绑定点击事件 -->
android:enabled="@{user.name.isNotEmpty()}"/> <!-- 动态控制启用状态 -->
</LinearLayout>
</layout>
2. Activity 代码(MainActivity.kt)
Kotlin
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.databindingdemo.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
// 只需要声明Binding对象
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 初始化Binding(替代setContentView和findViewById)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// 绑定数据(自动更新UI)
binding.user = User("张三", 20, true)
}
// 数据类(包含修改逻辑)
inner class User(
val name: String,
val age: Int,
val isStudent: Boolean
) {
// 点击事件处理
fun change() {
// 直接修改绑定的数据,UI自动更新
binding.user = if (name == "张三") {
User("李四", 25, false)
} else {
User("张三", 20, true)
}
}
}
}
三、核心差异对比
对比维度 | 传统方式 | Data Binding 方式 |
---|---|---|
控件获取 | 需手动写大量 findViewById |
自动生成 Binding 类,直接通过属性访问 |
UI 更新 | 需手动调用 setText() 等方法 |
数据变化后自动更新 UI |
代码量 | 多(初始化、更新逻辑重复) | 少(省略模板代码) |
可读性 | 数据与 UI 关联分散在代码中 | 数据与 UI 关联集中在布局中 |
维护成本 | 高(修改 UI 需同时改代码) | 低(布局与数据绑定一目了然) |
错误检查 | 运行时可能因控件 ID 错误崩溃 | 编译时检查绑定表达式,提前发现错误 |
事件处理 | 需手动设置 setOnClickListener |
布局中直接绑定事件,逻辑更集中 |
Data Binding 方式的区别
当使用 Data Binding 时,布局文件会被自动处理成一个 Binding 类 (比如 activity_main.xml
会生成 ActivityMainBinding
类),这个类相当于布局文件的 "代码代表"。
第一行:binding = ActivityMainBinding.inflate(layoutInflater)
ActivityMainBinding
:自动生成的类,名字是布局文件名(下划线转驼峰)+ Bindinginflate(layoutInflater)
:这是解析布局的过程,相当于传统的 "把 XML 变成 View"- 执行后,
binding
对象就持有了整个布局的所有控件和数据绑定能力
第二行:setContentView(binding.root)
binding.root
:指的是布局文件的根节点(比如你布局中的LinearLayout
或ConstraintLayout
)- 这行代码的作用和传统
setContentView(R.layout.xxx)
一样:让 Activity 显示这个根节点对应的界面 - 区别是:传统方式直接传布局 ID,Data Binding 方式传已经解析好的根 View
形象比喻
可以把布局文件想象成 "设计图纸":
- 传统方式:直接告诉 Activity "用图纸 ID 302 建房子"(
setContentView(R.layout.xxx)
),之后需要自己去房子里找各个房间(findViewById
)。 - Data Binding 方式:先请一个 "施工队"(
ActivityMainBinding.inflate()
)根据图纸建好房子,得到一个 "房屋管理手册"(binding
),手册里记录了所有房间的位置。然后告诉 Activity "就用这个建好的房子"(setContentView(binding.root)
),之后想找哪个房间,直接查手册就行(binding.tvName
)。