【问题标题】:ViewBinding vs Kotlin Android Extensions with synthetic viewsViewBinding vs Kotlin Android Extensions 与合成视图
【发布时间】:2020-02-09 13:42:07
【问题描述】:

新的ViewBinding 与带有合成视图绑定的Kotlin Android Extensions 相比如何?

除了新的 ViewBindings 提供的 NullSafety 和 TypeSafety 之外,我们为什么要考虑放弃 Kotlin 在 Views 上使用合成绑定的方式?

新的 ViewBinding 是否因为预先生成了 Binding 类而性能更高?

【问题讨论】:

标签: android kotlin kotlin-android-extensions android-viewbinding


【解决方案1】:

让我们回顾一下这两个。


配置

Kotlin Android 扩展

  1. 导入适当的布局合成扩展:import kotlinx.android.synthetic.main.<layout>.*
  2. 通过其 id 在代码中引用视图:textView.text = "Hello, world!"。这些扩展适用于:ActivitiesFragmentsViews

视图绑定

  1. 在你的类中创建绑定引用:private lateinit var binding YourClassBinding
  2. ActivityonCreate 中充气你的绑定binding = YourClassBinding.inflate(layoutInflater) 并调用setContentView(binding.root),或者在FragmentonCreateView 中充气然后返回:return binding.root
  3. 通过使用其 ID binding.textView.text = "Hello, world!" 绑定来引用代码中的视图

类型安全

Kotlin Android ExtensionsViewBinding 在定义上是类型安全的,因为引用的视图已经转换为适当的类型。


零安全

Kotlin Android ExtensionsViewBinding 都是 null 安全的。 ViewBinding 在这里没有任何优势。在 KAE 的情况下,如果视图仅存在于某些布局配置中,IDE 会为您指出:

所以你只要把它当作 Kotlin 中的任何其他可为空的类型,错误就会消失:


应用布局更改

如果是 Kotlin Android 扩展,布局更改会立即转化为合成扩展的生成,因此您可以立即使用它们。在 ViewBinding 的情况下,您必须构建您的项目


布局使用不正确

如果是 Kotlin Android Extensions,可能会导入不正确的布局合成扩展,从而导致NullPointerException。这同样适用于 ViewBinding,因为我们可以导入错误的 Binding 类。虽然,它是 与错误的类名相比,更容易忽略错误的导入,尤其是如果布局文件以Activity/Fragment/View 命名,因此 ViewBinding 在这里占上风。


KAE 与 ViewBinding 的总结

  • 类型安全 - 绘制。
  • 零安全 - 平局。
  • 样板代码 - KAE 获胜。来自 Kotlin Android 扩展documentation

Kotlin Android Extensions 插件允许我们获得相同的 我们对其中一些库的经验,无需添加 任何额外的代码。

  • 应用布局更改 - KAE 获胜。与 ViewBinding 相比,变化是即时的。
  • 布局使用不正确 - ViewBinding 获胜

我认为对于 ViewBinding 替代 KAE 存在很大的误解。人们听到大关键字并重复它们而无需事先验证。当然,ViewBinding 是目前 Java 开发的最佳选择(替代 ButterKnife),但与 Kotlin 中的 KAE 相比没有或几乎没有优势(请参阅布局使用不正确部分)。

旁注: 我相信 DataBinding 的人会喜欢 ViewBinding :)

【讨论】:

  • 你为什么不说在DataBinding中使用变量?我认为完全停止使用视图引用是必不可少的功能。顺便说一句,你可以通过<include ... />标签“扔”你的视图模型,这是另一个很大的优势。
  • @Ircover 问题是关于 KAE 和 ViewBinding 的比较。 DataBinding 不是该问题的一部分。
  • ViewBinding 在 null 安全性方面绝对具有优势。以 Fragment 生命周期为例:您可以在创建父布局之前在 onCreateView 中引用 KAE 中的视图。这将在编译时未被检测到,但在运行时抛出 NPE。使用 ViewBinding,您必须先引用父布局,然后才能引用其子布局
  • @BenLewis 如果您的绑定定义为lateinit,您仍然遇到同样的问题。这意味着在片段中编写代码时,您必须遵守一些严格的规则。
  • “应用布局更改” - 使用 ViewBinding 时,您不必构建项目,添加带有 id 的新视图后,您可以立即执行“binding.myTextView..”。
【解决方案2】:

ViewBinding解决了kotlinx.android.synthetic最大的问题。在synthetic 绑定中,如果您将内容视图设置为布局,然后键入仅存在于不同布局中的 id,IDE 允许您自动完成并添加新的导入语句。除非开发人员专门检查以确保他们的导入语句只导入正确的视图,否则没有安全的方法来验证这不会导致运行时问题。但是在ViewBinding 中,您应该使用layout 绑定对象来访问其视图,因此您永远不会调用不同布局中的视图,如果您想这样做,您将得到编译错误而不是运行时错误。这是一个例子。

我们创建了两个布局,分别称为 activity_mainactivity_other,如下所示:

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

    <TextView
        android:id="@+id/message_main"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

</RelativeLayout>

activity_other.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                >

    <TextView
        android:id="@+id/message_other"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

</RelativeLayout>

现在如果你这样写你的活动:

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_other.*

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //Application will crash because "message_other" doesn't exist in "activity_main"
        message_other.text = "Hello!"
    }
}

您的代码将无任何错误地编译,但您的应用程序将在运行时崩溃。因为message_other id 的视图在activity_main 中不存在,并且编译器没有检查这一点。但是如果你像这样使用ViewBinding

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        //This code will never compile and the IDE shows you an error
        binding.message_other.text = "Hello!"
    }
}

您的代码将永远无法编译,Android Studio 在最后一行显示错误。

【讨论】:

  • 您也可以使用 LayoutInflater 对 View 进行膨胀,然后通过变量引用其定义的字段。
  • 这在现实生活中似乎不太可能发生。
  • 这个例子没有意义。你用错了。为什么要导入不正确的东西 (activity_other) ?您使用不当的每个框架都可能导致问题。
  • @Bencri 布局配置不同可能会发生这种情况。
  • 正如@Bencri 所说,这不太可能发生,特别是如果您有自己的布局命名约定,根据它所属的屏幕命名这些视图。例如,您可以将 message_mainmessage_other 重命名为 main_messageother_message 以避免歧义。
【解决方案3】:

Kotlin Android Extensions 已在 Kotlin 1.4.20 中弃用,因此我建议使用 ViewBinding。

https://proandroiddev.com/migrating-the-deprecated-kotlin-android-extensions-compiler-plugin-to-viewbinding-d234c691dec7

【讨论】:

  • 这是我们应该使用 viewBinding 的最合理的理由。大声笑
  • 自从我写了那个答案后,我开始重构我的代码。有些事情使用合成更容易,但也更容易出错。发现了一些我用合成物制作的布局错误,而这些错误是用 ViewBinding 无法制作的。所以这是在速度和简洁性与稳定性之间的权衡,我认为这是朝着正确方向迈出的一步。
【解决方案4】:

kotlinx.android.synthetic 不再是推荐的做法,谷歌在一个提交消息中说“Reddit 线程之一

https://android-review.googlesource.com/c/platform/frameworks/support/+/882241 "

Synthetics 不是由 google 开发的,它是 JetBrains 制作的 kotlin android 扩展的一部分,并且逐渐 google android 开发人员开始在他们的演示和源代码中用 ViewBindins 替换 Synthetics。

“现在问题来了,我们必须考虑哪一个。”

根据 google(视图绑定、ButterKnife、Kotlin 合成),这些库已被许多应用程序成功使用并解决了相同的问题。

但对于大多数应用,谷歌建议尝试视图绑定而不是这些库因为视图绑定提供更安全、更简洁的视图查找。

附上参考图片以快速清除事物。

但是,如果您想进入部门,可以按照以下链接进行操作。 https://medium.com/androiddevelopers/use-view-binding-to-replace-findviewbyid-c83942471fc

【讨论】:

  • 1.始终为空安全 - 如果在膨胀之前或视图生命周期结束之后使用视图绑定仍然会崩溃 - 与合成没有什么不同 - 对于 ViewBinding 应该是 RED。 2. 仅引用当前布局中的 id - 这是真的,但 IDE 指出您要从哪个布局导入给定的 id,所以这不是一个大问题。 3. 支持 Kotlin 和 Java - 不好的说法,如果你可以在 android 开发中使用 Kotlin,那么为什么要使用 Java。 4. 需要的代码量 - Kotlin 合成的代码量最低,应该在表中非常低。
  • @xinaiz 为什么在充气之前使用它,请按照正确的方式使用它,否则肯定会遇到问题。你在投票和发表评论medium.com/androiddevelopers/…之前浏览过这个链接吗?
  • 是的,我前段时间读过。我没有在充气之前使用它,我只是说这是可能的。 “正确的方式”意味着有风险,对吧?另外,您跳过了or after view lifecycle ends 部分?
  • @xinaiz 2.但是,如果项目更大,则有可能使用错误的 id,如果多个开发人员在项目上工作,也有可能使用相同的资源名称。 3.是的,可能有一个项目要求,您必须同时使用 java 和 kotlin(如果项目已经在 java 中开发并开始使用 kotlin,那么肯定会有所帮助) 4. 对于 Synthetics,您必须导入单独的库,但对于视图绑定它已经存在于 Gradle 中,所以显然它需要更少的代码。
  • 回应4.什么库?它默认启用。这是关于apply plugin: 'kotlin-android-extensions'viewBinding { enabled = true } 的争论。差别不大。
猜你喜欢
  • 2018-03-10
  • 2019-06-10
  • 1970-01-01
  • 2021-11-18
  • 1970-01-01
  • 2020-06-10
  • 2021-11-28
  • 2018-02-07
  • 1970-01-01
相关资源
最近更新 更多