Kotlin 插件的落幕,ViewBinding 的崛起

简介: 我们看一下如何在项目中使用 DataBinding 和 ViewBinding,因文章篇幅原因,这里仅仅演示在 Activity 中使用,更多用法可以查看 Binding 库的示例。

image.png


前言



公众号:ByteCode,致力于分享最新技术原创文章,涉及 Kotlin、Jetpack、译文、系统源码、 LeetCode / 剑指 Offer / 多线程 / 国内外大厂算法题 等等一系列文章。


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


image.png


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


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


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


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


  • 使用 Kotlin 合成方法(Synthetic 视图)取代 findViewById,通过引入 kotlinx.android.synthetic 可以直接使用控件的 ID,我猜当初也是因为这个特性,吸引了很多开发者开始学习和尝试使用 Kotlin
  • 手动实现 Parcelize 比较麻烦,所以 Kotlin 提供了 @Parcelize 注解帮助快速实现 Parcelize


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


image.png


通过引入 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 和 DataBinding 它们的使用方式都比较复杂,稍后我会介绍一种方法,只需要一行代码即可使用 ViewBinding(视图绑定) 和 DataBinding(数据绑定),那么 ViewBinding 和 DataBinding 有什么区别呢?


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


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


// Android Studio 3.6
android {
    viewBinding {
        enabled = true
    }
    dataBinding{
        enabled = true
    }
}
// Android Studio 4.0
android {
    buildFeatures {
        dataBinding = true
        viewBinding = true
    }
}


接下来我们看一下如何在项目中使用 DataBinding 和 ViewBinding,因文章篇幅原因,这里仅仅演示在 Activity 中使用,更多用法可以查看 Binding 库的示例。


image.png


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


class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // Viewbinding
        val binding: 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 委托属性,简化模板代码。


因此我推出了一个新库 Binding ,Binding 简化 DataBinding 和 ViewBinding 的使用, 只需要一行代码即可实现 DataBinding 和 ViewBinding,他们的实现方式并不相同。


Binding 未来的规划提供通用的 findViewById 解决方案,因技术的迭代更新从 butterknife 、 DataBinding 、 Kotlin 合成方法(Synthetic 视图)到现在 ViewBinding , 未来也有可能出现新的技术,无论技术怎么变化,只需要更新 Binding ,对外的使用保持不变。我们来看一下如何在项目中使用 Binding 库。


  • 将下列代码添加在模块级 build.gradle 文件内,并且需要开启 DataBinding 或者 ViewBinding


dependencies {
    implementation 'com.hi-dhl:binding:1.0.4'
}


  • 在 Adapter(ListAdapter、PagingDataAdapter、RecyclerView.Adapter 等等)中使用 DataBinding 和 ViewBinding,添加 by viewbind() 或者 by databind() 即可,示例如下所示,查看详细示例


class ProductViewHolder(view: View) : RecyclerView.ViewHolder(view) {
    // 通过 DataBinding 绑定的 itemView
    val binding: RecycleItemProductBinding by databind()
    fun bindData(data: Product?, position: Int) {
        binding.apply {
            product = data
            executePendingBindings()
        }
    }
}
class ProductViewHolderHeader(view: View) : RecyclerView.ViewHolder(view) {
    // ViewBinding
    val binding: RecycleItemProductHeaderBinding by viewbind()
    fun bindData(data: Product?, position: Int) {
        binding.apply {
            name.text = "通过 ViewBinding 绑定的 head"
        }
    }
}


  • ActivityAppCompatActivityFragmentActivity 中使用,继承对应的类添加 by viewbind() 即可如下所示。


class MainActivity : AppCompatActivity() {
    // DataBinding
    val binding: ActivityMainBinding by databind(R.layout.activity_main)
    // ViewBinding
    val binding: ActivityMainBinding by viewbind()
}


  • Fragment 中使用方式如下所示。


class MainFragment : Fragment(R.layout.fragment_main) {
    // DataBinding
    val binding: FragmentMainBinding by databind()
    // ViewBinding
    val binding: FragmentMainBinding by viewbind()
}


  • Dialog 中使用方式如下所示。


class AppDialog(context: Context) : Dialog(context, R.style.AppDialog) {
    val binding: DialogAppBinding by viewbind()
}


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


class AppDialog(context: Context,lifecycle: Lifecycle) : Dialog(context, R.style.AppDialog) {
    val binding: DialogAppBinding by viewbind(lifecycle)
}


更多详细的用法,可以前去仓库 Binding 查看,Binding 具有以下优点:


  • 可以在  ActivityAppCompatActivityFragmentActivityFragmentDialogListAdapterPagingDataAdapterRecyclerView.Adapter 中的使用 DataBinding 或者 ViewBinding
  • 简单的 API 只需要一行代码即可实现 DataBinding 或者 ViewBinding
  • 避免大量的模板代码
  • 避免内存泄露,具有生命周期感知能力,当生命周期处于 onDestroyed() 时会自动销毁数据


源码分析,将会在后续的文章中分享,如果这个仓库对你有帮助,请在仓库右上角帮我 star 一下,非常感谢。


如何迁移 Parcelable



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


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


image.png


  • 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 等等开源库中学习到技巧。


陆陆续续有一些小伙伴们问我在哪里,可以看一些国外技术文章,所以我也给大家总结了一些不错的网站。


image.png


地址:https://site.51git.cn/gonav/2


全文到这里就结束了,如果有帮助 点个赞 就是对我最大的鼓励!!!


公众号:ByteCode,致力于分享最新技术原创文章,涉及 Kotlin、Jetpack、译文、系统源码、 LeetCode / 剑指 Offer / 多线程 / 国内外大厂算法题 等等一系列文章。


最后推荐我一直在更新维护的项目和网站:


  • 全新系列视频:现代 Android 开发 (MAD) 技巧系列教程:在线查看
  • 计划建立一个最全、最新的 AndroidX Jetpack 相关组件的实战项目 以及 相关组件原理分析文章,正在逐渐增加 Jetpack 新成员,仓库持续更新,欢迎前去查看:AndroidX-Jetpack-Practice
  • LeetCode / 剑指 offer / 国内外大厂面试题 / 多线程 题解,语言 Java 和 kotlin,包含多种解法、解题思路、时间复杂度、空间复杂度分析


image.png


  • 最新 Android 10 源码分析系列文章,了解系统源码,不仅有助于分析问题,在面试过程中,对我们也是非常有帮助的,仓库持续更新,欢迎前去查看 Android10-Source-Analysis
  • 整理和翻译一系列精选国外的技术文章,每篇文章都会有译者思考部分,对原文的更加深入的解读,仓库持续更新,欢迎前去查看 Technical-Article-Translation
  • 「为互联网人而设计,国内国外名站导航」涵括新闻、体育、生活、娱乐、设计、产品、运营、前端开发、Android 开发等等网址,欢迎前去查看 为互联网人而设计导航网站


历史文章




目录
相关文章
|
4月前
|
安全 Java Android开发
探索安卓开发的未来:Kotlin语言的崛起与挑战
在这篇文章中,我们将深入探讨Kotlin语言在安卓开发领域的应用及其对传统Java开发的颠覆性影响。通过分析Kotlin的特性、社区支持以及在实际项目中的应用案例,我们揭示了这一现代编程语言如何为开发者提供更简洁、更安全的编程体验,并讨论了它在面对性能优化和向后兼容性时所面临的挑战。文章旨在为读者呈现一个全面的视角,评估Kotlin作为未来安卓开发主流语言的可能性。
74 1
|
3月前
|
安全 Android开发 开发者
探索安卓开发的未来:Kotlin的崛起与Flutter的挑战
在移动开发的广阔天地中,安卓平台始终占据着举足轻重的地位。随着技术的不断进步和开发者需求的多样化,Kotlin和Flutter成为了改变游戏规则的新玩家。本文将深入探讨Kotlin如何以其现代化的特性赢得开发者的青睐,以及Flutter凭借跨平台的能力如何挑战传统的安卓开发模式。通过实际案例分析,我们将揭示这两种技术如何塑造未来的安卓应用开发。
84 6
|
5月前
|
Java Android开发 开发者
探索安卓应用开发的未来:Kotlin语言的崛起与挑战
【7月更文挑战第8天】随着移动设备在人们日常生活中扮演着越来越重要的角色,安卓应用开发的技术趋势和编程语言选择对开发者来说变得至关重要。本文将深入探讨Kotlin语言如何成为安卓开发的首选,分析其带来的优势及面临的挑战,并预测其未来的发展方向。
|
5月前
|
Dart Swift iOS开发
用pigeon kotlin swift写一个自己的插件
用pigeon kotlin swift写一个自己的插件
|
Android开发 Kotlin
kotlin新版本插件本地安装
kotlin新版本插件本地安装
|
XML Java 开发工具
使用 Kotlin 开发 Android 应用 | 8 个最优秀的 Android Studio 插件 Kotlin Android 素材
butterknife http://jakewharton.github.io/butterknife/ Annotate fields with @BindView and a view ID for Butter Knife to find an...
2047 0
|
Cloud Native 架构师 安全
Kotlin 异步框架 Ktor 2.0 发布,提供新的插件特性
Ktor 是一个用于创建异步客户端和服务器应用程序的Kotlin框架。经过 1 年多的开发,2.0版本于近日发布,在带来新特性的同时,也带来了破坏性的变化。
450 0
Kotlin 异步框架 Ktor 2.0 发布,提供新的插件特性
【JetPack】kotlin-android-extensions 插件 ( 视图绑定简单用法 )
【JetPack】kotlin-android-extensions 插件 ( 视图绑定简单用法 )
606 0
|
Java Maven Kotlin
使用 Kotlin , Groovy ,Java 开发一个自己的 Gradle 插件
使用 Kotlin , Groovy ,Java 开发一个自己的 Gradle 插件 先上效果图: image.png 功能说明: korGenerate: 自动生成 Entity,Dao,Controller 模板代码 ko...
1762 0
|
2月前
|
JSON 调度 数据库
Android面试之5个Kotlin深度面试题:协程、密封类和高阶函数
本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点。文章详细解析了Kotlin中的协程、扩展函数、高阶函数、密封类及`inline`和`reified`关键字在Android开发中的应用,帮助读者更好地理解和使用这些特性。
34 1