Kotlin 插件的落幕,ViewBinding 的崛起 | 开发者说·DTalk

原标题:Kotlin 插件的落幕,ViewBinding 的崛起 | 开发者说·DTalk

本文原作者: hi-dhl,原文发布于: ByteCode

https://mp.weixin.qq.com/s/FxrRyXp9-VDdv-mfkzsIsA

最近小伙们应该都会收到 Kotlin 1.4.20的升级通知,在 Kotlin 1.4.20中做了一个重要的更新 如下图所示:

简单总结一下,主要有以下几点:

  • 废弃了 kotlin-android-extensions 编译插件
  • Parcelable 相关的功能,移到了新的插件 kotlin-parcelize

按照 Google 的解释,kotlin-android-extensions插件只会保留至少一年的时间,将会在 2021 年 9 月或之后的 Kotlin 版本中移除

按照 Google 的解释,kotlin-android-extensions插件只会保留至少一年的时间,将会在 2021 年 9 月或之后的 Kotlin 版本中移除

kotlin-android-extensions主要有以下两个功能:

  • 使用 Kotlin 合成方法 (Synthetic 视图) 取代 findViewById,通过引入 kotlinx.android.synthetic可以直接使用控件的 ID,我猜当初也是因为这个特性,吸引了很多开发者开始学习和尝试使用 Kotlin

  • 手动实现 Parcelize比较麻烦,所以 Kotlin 提供了 @Parcelize注解帮助快速实现 Parcelize

使用 Kotlin 合成方法 (Synthetic 视图) 取代 findViewById,通过引入 kotlinx.android.synthetic可以直接使用控件的 ID,我猜当初也是因为这个特性,吸引了很多开发者开始学习和尝试使用 Kotlin

手动实现 Parcelize比较麻烦,所以 Kotlin 提供了 @Parcelize注解帮助快速实现 Parcelize

其实这并不是什么新的新闻了,早在 2019 年的时候,Google 就提出了不建议在项目中使用 kotlinx.android.synthetic,详见这个 commit ,部分内容如下图所示:

通过引入 kotlinx.android.synthetic可以直接使用控件的 ID,这么方便为什么不建议使用?主要有以下问题:

  • 通过 Kotlin 合成方法 (Synthetic 视图) 取代 findViewById ,这是通过全局空间缓存 ID,与 Layout 无关,没有针对 ID 进行无效检查
  • 在不同的 Layout 文件中,使用了相同的 ID,或者删除了 ID ,它并不会提示空异常,导致增加了 App 的崩溃次数
  • 仅仅支持 Kotlin
  • 默认是通过 HashMap 缓存 ID 浪费空间,虽然可以通过在模块级 build.gradle 文件内添加 defaultCacheImplementation = “SPARSE_ARRAY” 来修改默认的实现方式为 SparseArray
  • ……

因此 ViewBinding 出现了,ViewBinding 解决了上述所有问题,ViewBinding 虽然好,但是也有它的不足之处。

  • ViewBinding 相比于 kotlinx.android.synthetic使用方式比较复杂

  • ActivityFragmentDialogAdapter中 ViewBinding 和 DataBinding 初始化方式有些不同

  • 需要单独处理 includemerge标签的布局,和不带 merge标签的布局等等

  • DataBinding 结合 LiveData 一起使用需要做单独的处理

  • ……

ViewBinding 相比于 kotlinx.android.synthetic使用方式比较复杂

ActivityFragmentDialogAdapter中 ViewBinding 和 DataBinding 初始化方式有些不同

需要单独处理 includemerge标签的布局,和不带 merge标签的布局等等

DataBinding 结合 LiveData 一起使用需要做单独的处理

……

无论 ViewBinding 和 DataBinding 它们的使用方式都比较复杂,稍后我会介绍一种方法,只需要一行代码即可使用 ViewBinding (视图绑定) 和 DataBinding (数据绑定),那么 ViewBinding 和 DataBinding 有什么区别呢?

ViewBinding 和 DataBinding

ViewBinding:

  • 仅仅支持绑定 View

  • 不需要在布局文件中添加 layout 标签

  • 需要在模块级 build.gradle文件中添加 viewBinding = true即可使用

  • 效率高于 DataBinding,因为避免了与数据绑定相关的开销和性能问题

  • 相比于 kotlin-android-extensions插件避免了空异常

仅仅支持绑定 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 文件生成绑定类。

Android Studio 3.6版本开始,就内置在 Gradle 插件中了,不需要添加任何额外的库来使用它们,但是在 Android Studio 3.6Android Studio 4.0中使用方式不一样。

//Android Studio 4.0android{buildFeatures{dataBinding= trueviewBinding= true}}

接下来我们看一下如何在项目中使用 DataBinding 和 ViewBinding,因文章篇幅原因,这里仅仅演示在 Activity 中使用,更多用法可以查看 Binding 库中的示例。Binding 地址: https://github.com/hi-dhl/Binding

在模块级 build.gradle文件内开启 DataBinding 或者 ViewBinding 之后,需要在 Activity 中进行初始化,获取到 ViewBinding 实例即可使用。

overridefunonCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState)

// Viewbindingvalbinding: ActivityMainBinding = ActivityMainBinding.inflate(layoutInflater)

// DataBinding// val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)

with(binding){textView.setText( “Binding”) }}}

如果在每个 Activity 中都需要添加 ActivityMainBinding.inflate或者 DataBindingUtil.setContentView方法来进行初始化,这样无疑增加了很多模板代码,不仅仅是 Activity 在 Fragment、Dialog、Adapter 中都需要添加对应的方法来初始化。

那么能不能用一种方法,可以统一这些初始化方案,在 Kotlin 中是可以实现的,仅仅需要一行代码即可实现 DataBinding 和 ViewBinding。

一行代码实现 DataBinding 和 ViewBinding

如果在每个 ActivityFragmentDialogAdapter中都需要手动来添加相同的方法来初始化,这样的成本是非常大的,所以我们结合 Kotlin 委托属性,通过反射 inflate方法获取到 ViewBinding 实例,这样就可以直接使用 ID 了。

因此 Binding 库出现了,只需要一行代码即可实现 DataBinding 和 ViewBinding,这个库最初的思路源于 Simple one-liner ViewBinding in Fragments and Activities with Kotlin ,我们来看一下如何在项目中使用 Binding 库。

  • 将下列代码添加在模块级 build.gradle 文件内,并且需要开启 DataBinding 或者 ViewBinding
  • 在 Dialog 中使用方式如下所示

添加具有生命周期感知的 Dialog

  • 在 Activity 、 AppCompatActivity 、 FragmentActivity 中使用,继承对应的类添加 by viewbind 即可如下所示。

Fragment中使用方式如下所示。

Binding 库具有以下优点:

  • 可以在 Activity 、 AppCompatActivity 、 FragmentActivity 、 Fragment 、 Dialog 中的使用 DataBinding 或者 ViewBinding
  • 避免模板代码,只需要一行代码即可实现 DataBinding 或者 ViewBinding
  • 具有生命周期感知,当生命周期处于 onDestroyed 时会自动销毁数据

源码分析,将会在后续的文章中分享

如何迁移 Parcelable

Kotlin 将 Parcelable相关的功能,移到了新的插件 kotlin-parcelize,迁移只需要两步,如下所示。

  • 在模块级 build.gradle文件中,将 kotlin-android-extensions修改为 kotlin-parcelize

在模块级 build.gradle文件中,将 kotlin-android-extensions修改为 kotlin-parcelize

  • 将 import kotlinx.android.parcel.Parcelize 修改为 import kotlinx.parcelize.Parcelize 但是这一步不是必须的, kotlinx.android.parcel.Parcelize 可以继续使用,到目前为止还没有发现什么问题 (PS: 如果出现,只需要将包名替换就好)

结语

文章中相关的示例,已经上传到 GitHub 欢迎前去仓库 Binding查看。Binding 地址: https://github.com/hi-dhl/Binding

感谢 Simple one-liner ViewBinding in Fragments and Activities with Kotlin文章带来的思路,以及从 Anko、和 ViewBindingDelegate等等开源库中学习到技巧。

查看更多开发者精彩分享

“开发者说·DTalk” 面向中国开发者们征集 Google 移动应用 (apps & games) 相关的产品/技术内容。欢迎大家前来分享您对移动应用的行业洞察或见解、移动开发过程中的心得或新发现、以及应用出海的实战经验总结和相关产品的使用反馈等。我们由衷地希望可以给这些出众的中国开发者们提供更好展现自己、充分发挥自己特长的平台。我们将通过大家的技术内容着重选出优秀案例进行谷歌开发技术专家 (GDE) 的推荐。

责任编辑:

Thenews.cc