Administrator
发布于 2026-08-25 / 18 阅读
0
0

系列文章《Android 工程师的 100 篇进阶笔记》第 45 篇:ViewBinding 与 DataBinding 的取舍与迁移

上一篇聊了 Compose 自定义布局,这篇回到 View 体系,聊一个迁移期的经典问题——ViewBinding vs DataBinding。很多项目同时用了两者,代码混乱。到底该留哪个?怎么清理?

两者的本质区别

维度

ViewBinding

DataBinding

功能

只生成 View 引用

View 引用 + 数据绑定 + 双向绑定

编译速度

快(不解析表达式)

慢(需要解析 XML 表达式)

包体积

小(只生成引用代码)

大(运行时表达式引擎)

学习成本

极低

中(要学表达式语法)

推荐度

官方推荐

逐步边缘化

Google 的态度很明确:ViewBinding 是 View 体系下推荐的方案,DataBinding 只在需要数据绑定的场景保留。新项目不要用 DataBinding。

ViewBinding 用法

// build.gradle
android {
    viewBinding {
        enable = true
    }
}
// XML: activity_main.xml
// <TextView android:id="@+id/tvTitle" />
// <Button android:id="@+id/btnAction" />

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"
        binding.btnAction.setOnClickListener { /* ... */ }
    }
}

ViewBinding 生成的类名规则:XML 文件名转 PascalCase + "Binding"。activity_main.xml → ActivityMainBinding。

Fragment 中的用法

class MyFragment : Fragment() {
    private var _binding: MyFragmentBinding? = null
    private val binding get() = _binding!!

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

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null // 必须!Fragment 的 View 生命周期比 Fragment 短
    }
}

Fragment 中必须置空 binding,否则 View 销毁后还持有引用导致内存泄漏。这是 ViewBinding 最常见的坑。

RecyclerView Adapter 中的用法

class MyAdapter : RecyclerView.Adapter<MyAdapter.ViewHolder>() {
    class ViewHolder(val binding: ItemViewBinding) : RecyclerView.ViewHolder(binding.root)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding = ItemViewBinding.inflate(
            LayoutInflater.from(parent.context), parent, false
        )
        return ViewHolder(binding)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.binding.tvTitle.text = items[position].title
    }
}

include 布局的引用

<!-- activity_main.xml -->
<include android:id="@+id/includedLayout" layout="@layout/included_content" />
// included_layout.xml 里的 View 通过 binding.includedLayout.xxx 访问
binding.includedLayout.tvTitle.text = "Hello"

include 必须有 android:id,否则 ViewBinding 不会生成引用。

DataBinding 还在用的场景

如果项目已经有大量 DataBinding XML 表达式(@{}),不建议全部拆掉。常见还需要的场景:

  1. 双向绑定:@={viewModel.text} 可以自动同步 EditText 输入到 ViewModel

  2. 条件表达式:@{user.online ? visible : gone} 在 XML 里做显示控制

  3. BindingAdapter:自定义 XML 属性绑定逻辑

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

但说实话,这些场景用 Kotlin 代码实现也不复杂,而且更易调试。DataBinding 的 XML 表达式在编译期检查不严格,运行时才报错,调试体验不好。

混用时的注意事项

ViewBinding 和 DataBinding 可以同时使用。如果 XML 根节点有 <layout> 标签,会生成 DataBinding 类;否则生成 ViewBinding 类。

<!-- 这个 XML 生成 ViewBinding 类 -->
<LinearLayout>...</LinearLayout>

<!-- 这个 XML 生成 DataBinding 类 -->
<layout>
    <data>
        <variable name="user" type="com.example.User" />
    </data>
    <LinearLayout>...</LinearLayout>
</layout>

两种生成的类名规则不同:ViewBinding 是 XxxBinding,DataBinding 也是 XxxBinding,但 DataBinding 多了 bind() 方法和数据变量。

从 DataBinding 迁移到 ViewBinding

如果你决定清理 DataBinding:

  1. 删除 <layout> 标签,把 XML 恢复成普通布局

  2. 把 @{} 表达式改成代码赋值,移到 onBindViewHolder 或 onViewCreated

  3. BindingAdapter 改成扩展函数,在代码中调用

  4. 双向绑定改成 LiveData/Flow 观察,在代码中 afterTextChanged 时手动同步

这个过程比较繁琐但机械,适合分模块逐步进行。优先迁移简单页面,复杂的(有大量表达式)最后处理。

Compose 时代的终结

如果你的项目在向 Compose 迁移,ViewBinding 和 DataBinding 最终都会被替代。在 Compose 中不需要 View 引用:

@Composable
fun MyScreen(viewModel: MyViewModel = viewModel()) {
    val state by viewModel.state.collectAsState()
    Text(text = state.title)
    Button(onClick = { viewModel.onAction() }) { Text("Click") }
}

没有 binding,没有 findViewById,没有 NPE 风险。所以如果是新项目或大重构,直接上 Compose 比 ViewBinding 更省心。

小结

ViewBinding 是 View 体系下最简洁的方案,新项目直接用。DataBinding 在存量项目中可以保留但不要新增。长期目标是 Compose,ViewBinding 只是过渡。如果团队短期不打算上 Compose,ViewBinding 足够好用。

下一篇聊聊 Android Wear OS 开发要点。


评论