前言
2025年11月25日更新
JetBrains 和 Google 已于 2020 年宣布废弃 Kotlin Android Extensions(包括 synthetic),并在 Kotlin 1.8.0(2023 年初)中彻底移除支持。
所以现在只推荐使用
ViewBinding或者原始方式。
常见获取方式:
原始方式
在我们的开发过程中,需要获取XML布局文件中的ViewId,以便其赋值显示,我们习惯使用findViewById进行操作,可这样会导致很多的模版代码出现。
Butter Knife框架
直到Android大神 Jake Wharton开源了Butter Knife框架,通过Bind方式绑定获取ViewId。
基于Kotlin的扩展
近几年Android对Kotlin的支持,我们开始使用 Android Kotlin extensions。
在文件中导入布局文件直接引用viewId。无需做其他额外操作,最为方便。
生成代码的方式
谷歌在 Android Studio 3.6 Canary 11 及更高版本中加入了新的视图绑定方式ViewBinding。
注意:
要使用ViewBinding功能,AndroidStudio至少要升级到3.6。
ViewBinding和Kotlin扩展
ViewBinding 和 Kotlin 扩展 都是 Android 开发中常用的技术,用于简化视图查找和绑定的过程。
以下是它们之间的一些比较:
ViewBinding:
ViewBinding是由 Android 官方推荐和支持的库,从 Android Studio 3.6 版本开始引入。ViewBinding使用了编译时生成的绑定类,在xml布局文件中的每个视图都会生成一个对应的绑定类对象,因此在编译时检测到视图名称的错误。ViewBinding可以生成类型安全的代码,避免了手动查找和强制转换视图对象的麻烦。ViewBinding不会增加 APK 大小,因为它只是编译时生成的代码。- 在多个模块中引用同一个视图时可能会出现命名冲突的问题,需要通过手动指定全限定名解决。
Kotlin扩展:
Kotlin扩展是 Kotlin 语言的特性,其通过扩展函数的方式,允许开发者为现有的类添加新的函数或属性。Kotlin扩展使用起来相对简单,可以直接在布局文件中使用 Kotlin 扩展函数来查找和操作视图。Kotlin扩展对视图的数据获取和类型安全性没有提供直接的支持,需要手动处理可能的空指针异常和类型转换。Kotlin扩展会增加 APK 的大小,因为它是在运行时动态添加的函数。
总体而言
ViewBinding在类型安全性和编译时错误检测方面比Kotlin扩展更好。它是官方推荐的方式,并且可以避免一些潜在的运行时异常。
(2025.09.10更新)现在只推荐
ViewBinding,Kotlin 扩展已经不能用了,开发工具会报错。
搜索Kotlin扩展页面
搜索项目中所有使用Kotlin扩展的页面
搜索
1 | kotlinx.android.synthetic.main |
如果没有我们项目就可以移除synthetic。
ViewBinding说明
原理就是
Google在gradle插件中增加了新功能,当某个module开启ViewBinding功能后,编译的时候就去扫描此模块下的layout文件,生成对应的binding类。
开启ViewBinding
注意
只要开启后,会自动遍历layout下的xml文件自动生成对应的类。
版本对应关系
| Gradle 版本 | Android Gradle Plugin (AGP) |
|---|---|
| 8.4 | 8.3.0 |
| 8.2 | 8.2.0 |
| 8.0 | 8.1.0 |
| 7.5 | 7.4.2 |
| 7.4 | 7.3.1 |
| 6.1.1 | 4.0.2 |
新版本
从 Android Gradle Plugin 4.0.0 开始,ViewBinding 被正式支持,开启方式如下:
配置build.gradle
1 | android { |
旧版本
在 AGP 3.6 到 3.9 之间,ViewBinding 是作为实验性功能引入的,需要通过以下方式开启:
配置build.gradle
1 | android { |
使用
Activity中使用
原来的
1 | setContentView(R.layout.activity_tex) |
替换为
1 | private lateinit var binding: ActivityTexBinding |
使用
1 | val text = "$$ c = \\pm\\sqrt{a^2 + b^2} $$" |
完整代码
1 | import android.os.Bundle |
注意
ActivityTexBinding是自动生成的类,它会自动遍历layout下的xml文件自动生成对应的类。比如我的XML是
activity_tex.xml,它自动生成的类就是ActivityTexBinding。如果想在生成绑定类时忽略某个布局文件,将tools:viewBindingIgnore=”true”`属性添加到相应布局文件的根视图中。
Fragment中使用
fragment_pdf2.xml生成的文件是FragmentPdf2Binding
示例:
Kotlin
1 | class PdfFragment2(private val resource: YuxiResources) : Fragment() { |
Java
1 | public class MyFragment extends Fragment { |
Dialog中使用
1 | class MyDialog extends Dialog { |
Adapter 中使用
1 | public class MainAdapter extends RecyclerView.Adapter<MainAdapter.ViewHolder> { |
自定义View中使用
如果我们的自定义View中使用了layout布局,比如layout_my_view.xml,如下
1 |
|
会生成一个名为LayoutMyViewViewBinding.java文件,在自定义View通过如下方式绑定,
1 | public class MyView extends View { |
如果自定义View布局文件中使用merge标签,
1 |
|
此时要写成下面这个样子,
1 | LayoutMyViewViewBinding viewBinding = LayoutMyViewViewBinding.inflate(LayoutInflater.from(context), this); |
include标签的使用
不带 merge 标签
include 标签不带 merge 标签,需要给 include 标签添加 id, 直接使用 id 即可,用法如下所示。
1 | <include |
代码
1 | ActivityMainBinding binding = ActivityMainBinding.inflate(layoutInflater); |
注意
原来include的组件上可以直接添加事件,改为ViewBinding后必须找到子View再添加事件
比如
1 | include_title |
得改为
1 | binding.includeTitle.rlytBaseKey |
带 merge 标签
include 标签带 merge 标签,需要通过bind()将merge布局绑定到主布局上,用法如下所示。
1 | <include |
代码
1 | ActivityMainBinding binding = ActivityMainBinding.inflate(layoutInflater); |
迁移注意项
命名转换
XML 中的 progress_fl_main 用 binding.progress_fl_main 是找不到的,需要使用binding.progressFlMain
include
假如include的XML如下
1 | <include |
原来的
1 | include_class.visibility = View.GONE |
要改为
1 | binding.includeClass.root.visibility = View.GONE |
监听事件也要做类似的更改
1 | binding.includeClass.root.setOnTouchListener { |
注意
.root是 布局绑定类的核心属性,代表你通过<include>标签引入的子布局的根视图(Root View)。
基类
Activity
1 | abstract class BaseActivityVB<T : ViewBinding> : AppCompatActivity() { |
使用
1 | class MainActivity : BaseActivityVB<ActivityMainBinding>() { |
如果有多个泛型
Kotlin
1 | abstract class BaseMvpActivityVB<T : BasePresenter<*>, U : ViewBinding> : BaseActivityVB<U>(), BaseView { |
Java
1 | public abstract class BaseMvpActivityVB<T extends BasePresenter,U extends ViewBinding> |
Fragment
1 | import androidx.viewbinding.ViewBinding |
使用
1 | class FirstFragment : BaseFragmentVB<FragmentFirstBinding>() { |
如果有多个泛型
Kotlin
1 | abstract class BaseMvpFragmentVB<T : BasePresenter<*>?, U : ViewBinding> |
Java
1 | public abstract class BaseMvpFragmentVB<T extends BasePresenter, U extends ViewBinding> |
移除synthetic
迁移到 ViewBinding 后,可以完全移除 synthetic
在模块的 build.gradle 中 移除:
1 | id 'kotlin-android-extensions' |
或
1 | apply plugin: 'kotlin-android-extensions' |