当前位置:网站首页>竟然如此简单,DataBinding 和 ViewBinding
竟然如此简单,DataBinding 和 ViewBinding
2022-07-15 11:25:00 【hi-dhl】

前言
首先祝小伙伴们新年快乐,2020 一个不平凡的一年,2021 是你我新的起点。
2021 新签名:代码不止,文章不停。
2021 第一篇文章是对 2020 年末最后一篇文章 Kotlin 插件的落幕,ViewBinding 的崛起 的一个补充。
在之前的文章 Kotlin 插件的落幕,ViewBinding 的崛起 中介绍了 Google 为什么不建议在项目中使用 Kotlin 合成方法(Synthetic 视图), Google 建议使用 ViewBinding 替换 Kotlin 合成方法,那么 ViewBinding 和 DataBinding 都有什么区别。
ViewBinding:
- 仅仅支持绑定 View
- 不需要在布局文件中添加 layout 标签
- 需要在模块级
build.gradle文件中添加viewBinding = true即可使用 - 效率高于 DataBinding,因为避免了与数据绑定相关的开销和性能问题
- 相比于
kotlin-android-extensions插件避免了空异常
DataBinding:
- 包含了 ViewBinding 所有的功能
- 需要在模块级
build.gradle文件内添加dataBinding = true并且需要在布局文件中添加 layout 标签才可以使用 - 支持 data 和 view 双向绑定
- 效率低于 ViewBinding,因为注释处理器会影响数据绑定的构建时间。
ViewBinding 可以实现的, DataBinding 都可以实现,但是 DataBinding 的性能低于 ViewBinding,DataBinding 和 ViewBinding 会为每个 XML 文件生成绑定类。
R.layout.activity_main -> ActivityMainBinding
R.layout.fragment_main -> FragmentMainBinding
R.layout.dialog_app -> DialogAppBinding
在 Kotlin 插件的落幕,ViewBinding 的崛起 文章中同时也分析了 Kotlin 合成方法所带来的问题。即使 Kotlin 合成方法有很多问题,但是还有小伙伴愿意使用。
ViewBinding 和 DataBinding 为我们解决了这么多问题,但是为什么很多小伙伴们不愿意使用 ViewBinding 和 DataBinding,今天我们从使用的角度来分析。
ViewBinding 和 DataBinding
我大概汇总了 ViewBinding 和 DataBinding 在不同场景的所有用法,我们来看一下在项目中如何使用。
基本配置
从 Android Studio 3.6 版本开始,就内置在 Gradle 插件中了,不需要添加任何额外的库来使用它们,但是在 Android Studio 3.6 和 Android Studio 4.0 中使用方式不一样。
// Android Studio 3.6
android {
viewBinding {
enabled = true
}
dataBinding{
enabled = true
}
}
// Android Studio 4.0
android {
buildFeatures {
dataBinding = true
viewBinding = true
}
}
ViewBinding 的使用
因为涉及到的场景比较多,为了减少篇幅,我只列出来核心部分,如果之前从来没有用过,这里只需要知道 ViewBinding 的门槛比 Kotlin 合成方法要高即可。
不想为某个布局生成 binding 类,将下面属性添加到布局文件的根视图中
<LinearLayout tools:viewBindingIgnore="true" >
</LinearLayout>
在 Activity 中使用
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
}
在 Fragment 中使用
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val binding = FragmentViewBindBinding.inflate(inflater,container,false)
return binding.root
}
在 Adapter 中的使用
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
RecycleItemProductBinding.inflate(LayoutInflater.from(parent.context), parent, false)
}
在 Dialog 中使用
override fun onCreate(savedInstanceState: Bundle?) {
binding = DialogAppBinding.inflate(layoutInflater)
setContentView(binding.root)
}
include 标签的使用
include 标签不带 merge 标签,需要给 include 标签添加 id, 直接使用 id 即可,用法如下所示。
<include
android:id="@+id/include"
layout="@layout/layout_include_item" />
val binding: ActivityMainBinding = ActivityMainBinding.inflate(layoutInflater)
binding.include.includeTvTitle.setText("使用 include 布局中的控件, 不包含 merge")
include 标签带 merge 标签,注意这里和 DataBinding 用法不一样,给 include 标签添加 id,在 DataBinding 中可以直接使用 id,ViewBinding 则不行,ViewBinding 的用法如下所示。
<include layout="@layout/layout_merge_item" />
val binding: ActivityMainBinding = ActivityMainBinding.inflate(layoutInflater)
val mergeItemBinding = LayoutMergeItemBinding.bind(binding.root)
mergeItemBinding.mergeTvTitle.setText("使用 include 布局中的控件, 包含 merge")
ViewStub 标签的使用
根据实践证明,截止到这篇文章发布时,在 Android Studio 4.2.0 bata 2 中,无法直接在 ViewBinding 布局中使用 ViewStub 标签,仅仅只能在 DataBinding 布局(带 layout 标签)中使用,详见 issue
因为没有找到比较权威的资料证明,这里建议小伙们直接在项目 Binding 中进行尝试,如果有其他在 ViewBinding 布局中的实现方式,欢迎留言告知我
DataBinding 的使用
因为涉及到的场景比较多,为了减少篇幅,我只列出来核心部分,如果之前从来没有用过,这里只需要知道 DataBinding 的门槛比 Kotlin 合成方法要高即可。
需要给布局文件添加 layout 标签
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout...>
...
</LinearLayout
</layout>
在 Activity 中使用
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.lifecycleOwner = this
setContentView(binding.root)
}
在 Fragment 中使用
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val binding = FragmentViewBindBinding.inflate(inflater,container,false)
binding.lifecycleOwner = this
return binding.root
}
在 Adapter 中的使用
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
val bidning:RecycleItemProductBinding = DataBindingUtil.bind(view)
}
在 Dialog 中使用
override fun onCreate(savedInstanceState: Bundle?) {
binding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.dialog_data_binding, null, false)
setContentView(binding.root)
}
include 标签的使用
include 标签不带 merge 标签,需要给 include 标签添加 id, 直接使用 id 即可。
<include
android:id="@+id/includeData"
layout="@layout/layout_include_data_item"/>
val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.includeData.includeTvTitle.setText("通过代码设置 include layout 的控件")
include 标签带 merge 标签,注意这里和 ViewBinding 用法不一样,给 include 标签添加 id,在 DataBinding 中可以直接使用,在 ViewBinding 中则不行。
<include
android:id="@+id/includeDataMerge"
layout="@layout/layout_merge_data_item"/>
val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.includeDataMerge.mergeTvTitle.setText("通过代码设置 merge layout 的控件")
ViewStub 标签的使用
给 ViewStub 标签添加 id, 在 DataBinding 中可以直接使用 id 即可。
<ViewStub
android:id="@+id/stub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout="@layout/view_stub" />
binding.stub.setOnInflateListener { stub, inflated ->
// ViewBinding
val viewStub: ViewStubBinding = ViewStubBinding.bind(inflated)
viewStub.tvTitle.setText("使用 ViewStub 加载 ViewBinding 布局")
}
binding.stub.setOnInflateListener { stub, inflated ->
// DataBinding
val dataViewStub: ViewStubDataBinding = DataBindingUtil.bind(inflated)!!
dataViewStub.tvTitle.setText("使用 ViewStub 加载 DataBinding 布局")
}
if (!binding.stub.isInflated) {
binding.stub.viewStub!!.inflate()
}
正如你所见,在 Ativity 、 Fragment 、 Dialog 、 Adapter 、 include 、 merge 、 ViewStub 等等场景中,使用 ViewBinding 或者 DataBinding 都要进行不同的处理,相比于 Kotlin 合成方法,这使用门槛太高了。
那么能不能用一种方法,可以统一这些初始化方案,在 Kotlin 中仅仅需要一行代码即可实现 DataBinding 和 ViewBinding。
一行代码
如果在每个场景中都需要手动进行不同的处理,这样的成本是非常大的,因此我推出了一个新库 Binding ,Binding 结合 Kotlin 委托属性,统一封装了 DataBinding 和 ViewBinding 不同的处理, 提供了简单的 API 如下所示。
ViewBinding 中的使用
val binding: ActivityViewBindBinding by viewbind()
DataBinding 中的使用
val binding: ActivityDataBindBinding by databind(R.layout.activity_data_bind)
或者
val binding: ActivityDataBindBinding by databind()
正如你所见,只需要简单的几个 API 即可实现上述所有场景,我们先来介绍一下 Binding。
Binding 未来的规划提供通用的 findViewById 解决方案,因技术的迭代更新从 butterknife 、 DataBinding 、 Kotlin 合成方法(Synthetic 视图)到现在 ViewBinding , 未来也有可能出现新的技术,无论技术怎么变化,只要 Binding 对外的使用保持不变,只需要更新 Binding ,即可完成迁移。
Binding 具有以下优点:
- 提供了很多实战案例包含
Ativity、Fragment、Dialog、Adapter、include、merge、ViewStub、Navigation、 数据双向绑定 等等场景 - 简单的 API 只需要一行代码即可实现 DataBinding 或者 ViewBinding
- 支持在
Activity、AppCompatActivity、FragmentActivity、Fragment、Dialog中的使用 DataBinding 或者 ViewBinding - 支持在
ListAdapter、PagedListAdapter、PagingDataAdapter、RecyclerView.Adapter中的使用 DataBinding 或者 ViewBinding - 支持在 Navigaion Fragment 管理框架、 BottomSheetDialogFragment 等等场景中使用 DataBinding 和 ViewBinding
- 避免大量的模板代码
- 避免内存泄露,具有生命周期感知能力,当生命周期处于
onDestroyed()时会自动销毁数据
接下来我们一起来分析一下如何在项目中使用 Binding,将下列代码添加在模块级 build.gradle 文件内,并且需要开启 DataBinding 或者 ViewBinding。
dependencies {
implementation 'com.hi-dhl:binding:1.0.7'
}
在 Activity 、AppCompatActivity 、FragmentActivity 中使用,添加 by viewbind() 或者 by databind(R.layout.activity_main) 即可,示例如下所示。
class MainActivity : AppCompatActivity() {
// DataBinding
val binding: ActivityMainBinding by databind(R.layout.activity_main)
// ViewBinding
val binding: ActivityMainBinding by viewbind()
}
在 Fragment 中提供了两种方式:
- 方式一:在
onCreateView中使用,这种方式适用于所有使用Fragment的场景 - 方式二:在
onViewCreated中使用
方式一:
class FragmentNav1 : Fragment(R.layout.fragment_main) {
// DataBinding
val binding: FragmentMainBinding by databind()
// ViewBinding
val binding: FragmentMainBinding by viewbind()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return binding.root
}
}
方式二,需要注意以下几点:
- 不能在
Navigaion Fragment和BottomSheetDialogFragment中使用 - 在其他 Fragment 场景中,如果使用
方式二界面不显示,改用方式一即可解决
class FragmentNav1 : Fragment(R.layout.fragment_main) {
// DataBinding
val binding: FragmentMainBinding by databind()
// ViewBinding
val binding: FragmentMainBinding by viewbind()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.apply { textView.setText("Binding") }
}
}
在 Dialog 中使用方式如下所示。
class AppDialog(context: Context) : Dialog(context, R.style.AppDialog) {
// DataBinding
val binding: DialogAppBinding by databind(R.layout.dialog_data_binding)
// ViewBinding
val binding: DialogAppBinding by viewbind()
}
或者添加具有生命周期感知的 Dialog。
class AppDialog(context: Context,lifecycle: Lifecycle) : Dialog(context, R.style.AppDialog) {
// DataBinding 监听生命周期
val binding: DialogAppBinding by databind(R.layout.dialog_data_binding, lifecycle)
// ViewBinding 监听生命周期
val binding: DialogAppBinding by viewbind(lifecycle)
}
在 Adapter 中使用 DataBinding 和 ViewBinding,只需要在 ViewHolder 中添加 by viewbind() 或者 by databind() 即可,示例如下所示。
class ProductViewHolder(view: View) : RecyclerView.ViewHolder(view) {
// DataBinding
val binding: RecycleItemProductBinding by databind()
// ViewBinding
val binding: RecycleItemProductHeaderBinding by viewbind()
}
扩展方法,支持 DataBinding 初始化的时候绑定数据。
val binding: ActivityDataBindBinding by databind(R.layout.activity_data_bind) {
val account = Account()
account.name = "test"
this.account = account
}
上面只是常见的几种用法,当然还有更多实战案例(include 、 merge 、 ViewStub 、 Navigation 、 数据双向绑定 等等)已经上传到 GitHub 欢迎前去仓库 Binding 查看。
GitHub 仓库: https://github.com/hi-dhl/Binding
这篇文章可以理解为对之前的文章 Kotlin 插件的落幕,ViewBinding 的崛起 的一个补充,从使用的角度分析了 DataBinding 和 ViewBinding 不同之处,同时也介绍了如何用更简单的方式实现 DataBinding 和 ViewBinding。
全文到这里就结束了,如果有帮助 点个赞 就是对我最大的鼓励
代码不止,文章不停
持续分享最新的技术
最后推荐我一直在更新维护的项目和网站:
全新系列视频:现代 Android 开发 (MAD) 技巧系列教程:在线查看
计划建立一个最全、最新的 AndroidX Jetpack 相关组件的实战项目 以及 相关组件原理分析文章,正在逐渐增加 Jetpack 新成员,仓库持续更新,欢迎前去查看:AndroidX-Jetpack-Practice
LeetCode / 剑指 offer / 国内外大厂面试题 / 多线程 题解,语言 Java 和 kotlin,包含多种解法、解题思路、时间复杂度、空间复杂度分析

最新 Android 10 源码分析系列文章,了解系统源码,不仅有助于分析问题,在面试过程中,对我们也是非常有帮助的,仓库持续更新,欢迎前去查看 Android10-Source-Analysis
整理和翻译一系列精选国外的技术文章,每篇文章都会有译者思考部分,对原文的更加深入的解读,仓库持续更新,欢迎前去查看 Technical-Article-Translation
「为互联网人而设计,国内国外名站导航」涵括新闻、体育、生活、娱乐、设计、产品、运营、前端开发、Android 开发等等网址,欢迎前去查看 为互联网人而设计导航网站
边栏推荐
- mysql show variables 查的是哪个表里面的数据?
- Chapter 8 delegates, lambda expressions, and events
- Summer learning plan [activities]
- H5 open wechat applet
- Experiment 2 Data modeling of after sales service management system
- 推特大战马斯克:想走,哪那么容易
- Involve yourself? After imagen, it launched an image model generated by 20billion text, which stunned netizens!
- Twitter vs musk: it's not that easy to leave
- 3DS max: customizing shelves
- The domain name has been filed, and the trading is strictly controlled. Do you know?
猜你喜欢

How can Volvo be confident to maintain "zero casualties" in traffic safety in the era of electrification?

实验1.SQL Server的安全机制

diffusion model

上海港口航运人工智能集装箱人工智能独角兽中集飞瞳,港航人工智能产品市场占有率领先,带动港航人工智能集装箱人工智能全产业链发展

许式伟:Go+ 演进之路

41:第四章:开发文件服务:2:FastDFS:(2):准备两个虚拟机,然后创建两个FastDFS基础环境;一台虚拟机上配置tracker服务;另一台虚拟机上配置storage服务;
![[hero planet July training leetcode problem solving daily] 15th binary tree](/img/01/89e2c60fade3148ca658551ac41b23.png)
[hero planet July training leetcode problem solving daily] 15th binary tree

【福利活动】给你的代码叠个 Buff!点击“茶”收好礼

51 single chip microcomputer serial port baud rate (keep it and don't look everywhere)

【招募】2022向光奖|年度ESG影响力投资奖正式启动!
随机推荐
实验3.选课系统
云呐-机房动环监控扩容方案
tree shaking的原理是什么?
Raspberry pie remote desktop display is incomplete
1750 万美元,Oracle 就集体诉讼案达成和解!
41: Chapter 4: develop file services: 2:fastdfs: (2): prepare two virtual machines, and then create two fastdfs basic environments; Configure tracker service on a virtual machine; Configure storage se
Dragon lizard community recruitment Promotion Ambassador & experience officer| Everyone can participate in open source
Heap sort
MySQL batch add test data
许式伟:Go+ 演进之路
2022 global developer salary PK: China ranks 19th, and using go language is the most profitable
Single vehicle management system - 1 Document design and SQL code description
Experiment 3 Course selection system
Latex數學公式
毕业即失业?
实验1.SQL Server的安全机制
互联网还有未来吗?
The domain name has been filed, and the trading is strictly controlled. Do you know?
three.js无限跑动VR小游戏
[NLP] deepke, an open source knowledge extraction tool that supports low resources, long chapters and multimodality