迁移被废弃的Kotlin Android Extensions插件

1,507 阅读3分钟

在Kotlin 1.4.20-M2中,JetBrains废弃了Kotlin Android Extensions编译插件。

其实这是早就预料到的,你可以在这次提交中看到详情。

kotlinx.android.synthetic不再是一个推荐的做法。删除了显式的findViewById。

但为什么呢?

kotlinx的合成属性存在一些众所周知的问题。

它公开了以view的id为名的全局变量,但该名称与实际的布局无关,没有针对无效查找进行检查。
它只适用于Kotlin。
当View只存在于某些配置中时,它们没有空安全提示。
所有这些问题加在一起,导致增加了Android应用的崩溃次数。
另外谷歌正在推广模块化,但合成属性不能跨模块工作。这是自20181月以来的一个公开问题。

有哪些替代方案?

View Binding是视图查找以及绑定的推荐方案,但与Android Kotlin Extensions相比,它确实增加了一些开销。但它增加了编译时对视图查找的检查和类型安全。
传统方式findViewById,Kotlin和Java都适用。

JetBrains废弃了Kotlin Android Extensions,推荐使用View Binding,所以我们将在本文中探讨如何迁移到View Binding。 View Binding

不要与Data Binding混淆

View Binding是一种功能,它允许您更容易地编写与视图交互的代码。

一旦在一个模块中启用了View Binding,它就会为该模块中存在的每个 XML 布局文件生成一个绑定类。

绑定类的实例包含对相应布局中具有ID的所有VIew的直接引用。

View Binding对于在多个配置中定义的布局来说是Null-safe的。

View Binding将检测视图是否只存在于某些配置中,并创建一个@Nullable属性。

View Binding适用于Java和Kotlin。 如何启用View Binding?

你不需要添加任何额外的库来启用View Binding。从Android Studio 3.6版本开始,它就被内置到Android Gradle Plugin中了。如果要在模块中启用该功能,请在你的build.gradle文件中添加以下内容。

android { ... buildFeatures { viewBinding true } }

如何使用View Binding?

如果为模块启用了View Binding,则会为模块包含的每个 XML 布局文件生成一个绑定类。

每个绑定类都包含对根视图和所有具有ID的视图的引用。

绑定类的名称是通过将 XML 文件的名称转换为驼峰式大小写,并在结尾处添加 Binding 一词来生成的。

**译者注:**例如,假设某个布局文件的名称为 result_profile.xml,所生成的绑定类的名称就为 ResultProfileBinding 在Activity中使用View Binding

private lateinit var binding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) }

然后可以使用binding对象访问视图:

binding.name.text = "Some Text"

1

在Fragment中使用View Binding

在Fragment中使用View Binding需要多加注意,如果使用不当它会引发内存泄漏,如果你没有在onDestroy中将view置空,那么它就不会从内存中清除。

private var _binding: FragmentMainBinding? = null private val binding get() = _binding!!

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

override fun onDestroyView() { super.onDestroyView() _binding = null }

然后就可以像我们在Activity中那样使用它。

binding.name.text = "Some Text"