ViewBinding vs DataBinding 深度对比

ViewBinding vs DataBinding 深度对比

选择最适合你的视图绑定方案

目录

  1. 两者概述
  2. ViewBinding 用法
  3. DataBinding 用法
  4. 功能对比
  5. 性能对比
  6. 选择建议

1. 两者概述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
┌─────────────────────────────────────────────────────────────────────┐
│ ViewBinding vs DataBinding │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ViewBinding (2019) │
│ ├── 只生成绑定类,不修改布局文件 │
│ ├── 只读,的单向绑定 │
│ ├── 无需额外运行时开销 │
│ └── 不支持 XML 表达式 │
│ │
│ DataBinding (2015) │
│ ├── 生成绑定类 + 修改布局文件 │
│ ├── 支持双向绑定 (@={}) │
│ ├── 支持 XML 表达式和事件处理 │
│ └── 有运行时开销 │
│ │
└─────────────────────────────────────────────────────────────────────┘

2. ViewBinding 用法

启用

1
2
3
4
5
6
7
8
// build.gradle (app)
android {
buildFeatures {
viewBinding {
enabled = true
}
}
}

基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

<Button
android:id="@+id/btnClick"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

</LinearLayout>

// Activity 中使用
class MainActivity : AppCompatActivity() {

// 自动生成的绑定类
private lateinit var binding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

// 绑定视图
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)

// 使用视图
binding.tvTitle.text = "Hello ViewBinding"

// 点击事件
binding.btnClick.setOnClickListener {
// 处理点击
}
}
}

Fragment 中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class MyFragment : Fragment() {

private var _binding: FragmentMyBinding? = null
private val binding get() = _binding!!

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentMyBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

binding.tvTitle.text = "Hello"
}

override fun onDestroyView() {
super.onDestroyView()
_binding = null // 防止内存泄漏
}
}

3. DataBinding 用法

启用

1
2
3
4
5
6
// build.gradle (app)
android {
dataBinding {
enabled = true
}
}

布局文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!-- activity_main.xml -->
<layout xmlns:android="http://schemas.android.com/apk/res/android">

<!-- 数据变量 -->
<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:text="@{user.name}" />

<!-- 双向绑定 -->
<EditText
android:text="@={user.email}" />

<!-- 事件绑定 -->
<Button
android:onClick="@{() -> viewModel.onButtonClick()}" />

</LinearLayout>
</layout>

Activity 使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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("John", "john@example.com")
binding.user = user

// 设置 LifecycleOwner (观察数据变化)
binding.lifecycleOwner = this

// 或者使用 ViewModel
binding.viewModel = viewModel
}
}

XML 表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 字符串拼接
android:text="@{`Hello ` + user.name}"

// 方法调用
android:text="@{viewModel.getDisplayName(user)}"

// Null 安全
android:text="@{user.name ?? `Default`}"

// 资源引用
android:text="@string/app_name"

// 颜色
android:textColor="@{isError ? @color/red : @color/black}"

4. 功能对比

功能对比表

功能 ViewBinding DataBinding
代码生成
布局修改 ✅ 需要 <layout>
单向绑定
双向绑定 ✅ (@={})
XML 表达式
事件绑定
自定义 Binding
Observable 字段
编译检查 部分 ✅ 完整

双向绑定

1
2
3
4
5
6
7
8
// DataBinding 双向绑定
// 布局中
<EditText
android:text="@={user.name}" />

// 自动更新
user.name = "New Name" // EditText 自动更新
// 用户输入 // user.name 自动更新

自定义 Binding

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 自定义 Binding 方法
class BindingAdapters {

@JvmStatic
@BindingAdapter("imageUrl")
fun loadImage(view: ImageView, url: String?) {
url?.let {
Glide.with(view.context).load(it).into(view)
}
}

@JvmStatic
@BindingAdapter("visible")
fun setVisible(view: View, visible: Boolean) {
view.visibility = if (visible) View.VISIBLE else View.GONE
}

@JvmStatic
@BindingAdapter("onSearch")
fun setSearchListener(view: EditText, listener: (String) -> Unit) {
view.setOnEditorActionListener { _, _, _ ->
listener(view.text.toString())
true
}
}
}

// 使用
<ImageView
app:imageUrl="@{user.avatarUrl}"
app:visible="@{!user.avatarUrl.isEmpty()}" />

5. 性能对比

性能差异

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
┌─────────────────────────────────────────────────────────────────────┐
│ 性能对比 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ViewBinding: │
│ ├── 编译时生成绑定类 │
│ ├── 运行时开销: 0 │
│ ├── 内存: 只有 View 引用 │
│ └── 编译速度: 快 │
│ │
│ DataBinding: │
│ ├── 编译时生成绑定类 + 额外代码 │
│ ├── 运行时开销: 观察者模式 │
│ ├── 内存: View + Data + Observer │
│ └── 编译速度: 慢 (需要处理表达式) │
│ │
│ 结论: ViewBinding 性能更好 │
│ │
└─────────────────────────────────────────────────────────────────────┘

编译时间影响

1
2
3
4
5
# 测量方式
./gradlew assembleDebug --profile

# DataBinding 编译时间增加约 10-20%
# ViewBinding 增加约 2-5%

6. 选择建议

决策树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
需要双向绑定?

├─▶ 是 ──▶ DataBinding

└─▶ 否

├─▶ 需要 XML 表达式?
│ │
│ ├─▶ 是 ──▶ DataBinding
│ │
│ └─▶ 否
│ │
├─▶ 需要事件绑定?
│ │
│ ├─▶ 是 ──▶ DataBinding
│ │
│ └─▶ 否
│ │
└─▶ ViewBinding (推荐)

实际建议

场景 推荐
简单列表展示 ViewBinding
表单输入 DataBinding
MVVM + LiveData DataBinding
只需 View 引用 ViewBinding
追求性能 ViewBinding
复杂 UI 逻辑 DataBinding

混合使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 可以同时启用两者
android {
buildFeatures {
viewBinding {
enabled = true
}
dataBinding {
enabled = true
}
}
}

// 按需使用
// 简单页面: ViewBinding
// 复杂页面: DataBinding

总结

1
2
3
4
5
6
7
选择原则:
─────────────────────────────────────────
简单页面 → ViewBinding (性能好)
复杂交互 → DataBinding (功能强)
MVVM 架构 → DataBinding
性能优先 → ViewBinding
─────────────────────────────────────────

相关文章