Kotlin Android View Binding:findViewById vs Butterknife vs Kotlin Android Extension

问题描述 投票:17回答:4

我正试图找出在Kotlin中进行Android View Binding的最佳方法。似乎有一些选择:

findViewById

val button: Button by lazy { findViewById<Button>(R.id.button) }

牛油刀

https://github.com/JakeWharton/butterknife

@BindView(R.id.button) lateinit var button: Button

Kotlin Android扩展程序

https://kotlinlang.org/docs/tutorials/android-plugin.html

import kotlinx.android.synthetic.main.activity_main.*

我对java版本中的findViewById和Butterknife非常熟悉,但Kotlin中每种视图绑定方法的优缺点是什么?

Kotlin Android扩展程序与RecyclerView + ViewHolder模式相匹配吗?

另外,Kotlin Android Extensions如何通过q​​azxswpoi处理嵌套视图的视图绑定?

例如:对于使用include的活动,如何访问activity_main.xml

activity_main.xml中

View custom1

custom.xml

<...>
    <include layout="@layout/custom" android:id="@+id/custom" />
</>
android kotlin findviewbyid butterknife kotlin-android-extensions
4个回答
13
投票

<...> <View android:id="@+id/custom1" ... /> <View android:id="@+id/custom2" ... /> </> kotlin-android-extensions更好。 ButterKnife也不错,但Kotlin在这里是一个更好,更明智的选择。

原因:kotlin-android-extensions使用Kotlin属性,并使用synthetic按需调用(因此轻微的快速活动/片段加载),而caching function一次绑定ButterKnife上的所有视图(消耗更多的时间)。使用ButterKnife.bind(),您甚至不需要使用注释来绑定视图。

是的它也可以与RecyclerView + ViewHolder模式一起使用,你只需要导入Kotlin(如果kotlinx.android.synthetic.main.layout_main.view.*是Activity / Fragment布局文件名)。

您不需要为使用layout_main.xml导入的布局做任何额外的工作。只需使用导入视图的ID即可。

请查看以下官方文档说明:

Kotlin Android Extensions是Kotlin编译器的插件,它做了两件事:

  1. 在每个Kotlin Activity中添加隐藏的缓存功能和字段。该方法非常小,因此它不会增加APK的大小。
  2. 用函数调用替换每个合成属性调用。 这是如何工作的,当调用合成属性时,接收器是模块源中的Kotlin Activity / Fragment类,调用缓存函数。例如,给定
include

在MyActivity中生成隐藏的缓存函数,因此我们可以使用缓存机制。

但是在以下情况中:

class MyActivity : Activity()
fun MyActivity.a() { 
    this.textView.setText(“”)
}

我们不知道是否仅在来自我们的源的活动或普通Java活动上调用此函数。因此,我们不在那里使用缓存,即使前一个示例中的MyActivity实例是接收者。

链接到上面的fun Activity.b() { this.textView.setText(“”) }

我希望它有所帮助。


4
投票

我无法将此问题标记为重复,因为您要求在不同问题下回答/讨论过多个问题。

Kotlin中每种视图绑定方法的优缺点是什么?

这已经讨论过documentation page

Kotlin Android Extensions如何通过include处理嵌套视图的视图绑定?例如:对于使用activity_main.xml的Activity,如何访问View custom1?

所有Kotlin Android Extensions都会为您调用here。见findViewById

Kotlin Android扩展程序与RecyclerView + ViewHolder模式相匹配吗?

是的,它确实。但是,您必须使用将从中获取的视图保存到属性中,因为它们没有像“活动”或“片段”中那样的缓存。见here


如果您仍有未回答的问题,请随时要求澄清。


4
投票

小心使用

here

当视图被破坏时我已经遇到了问题,并且当你的片段实例存活下来时(我认为在活动的情况下它不适用),它们持有引用旧视图的惰性属性。

例:

你在布局中有一个静态值,比方说val button: Button by lazy { findViewById<Button>(R.id.button) }

android:text="foo"

然后片段被破坏,因为你替换它,但然后你回来,它再次重新生成callin onCreateView。

//calling first time
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
    button.setText("bar")
    // button is called for the first time, 
    // then button is the view created recently and shows "bar"
}

0
投票

如果你使用datainding库。你应该数据绑定视图绑定。

因为它比kotlin扩展更明确

p.s findviewbyid非常不便和样板代码


0
投票

现在有第四种选择,称为//calling second after destroyed override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { button.setText(Date().time.toString()) //button is already set, then you are setting the value the to old view reference // and in your new button the value won't be assigned // The text showed in the button will be "foo" } ,可与View Binding一起使用

引自Android Studio 3.6 Carnary 11

查看绑定

视图绑定是一项功能,使您可以更轻松地编写与视图交互的代码。在模块中启用视图绑定后,它会为该模块中存在的每个XML布局文件生成一个绑定类。绑定类的实例包含对相应布局中具有ID的所有视图的直接引用。

在大多数情况下,视图绑定取代了docs.


findViewById的区别

与使用findViewById相比,View绑定具有重要优势:

  • 空安全性:由于视图绑定会创建对视图的直接引用,因此由于视图ID无效,因此不存在空指针异常的风险。此外,当视图仅出现在布局的某些配置中时,在绑定类中包含其引用的字段将标记为findViewById
  • 类型安全:每个绑定类中的字段具有与它们在XML文件中引用的视图匹配的类型。这意味着没有类强制转换异常的风险。

与数据绑定库的差异

视图绑定和数据绑定库都生成可用于直接引用视图的绑定类。但是,存在显着差异:

  • 数据绑定库仅处理使用@Nullable标记创建的数据绑定布局。
  • 视图绑定不支持布局变量或布局表达式,因此它不能用于将布局与XML中的数据绑定。

用法

要利用项目模块中的View绑定,请将以下行添加到其<layout>文件中:

build.gradle

例如,给定一个名为android { viewBinding.enabled = true } 的布局文件:

result_profile.xml

在这个例子中,你可以在<LinearLayout ... > <TextView android:id="@+id/name" /> <ImageView android:cropToPadding="true" /> <Button android:id="@+id/button" android:background="@drawable/rounded_button" /> </LinearLayout> 中调用ResultProfileBinding.inflate()

activity

现在可以使用绑定类的实例来引用任何视图:

private lateinit var binding: ResultProfileBinding

@Override
fun onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)
    binding = ResultProfileBinding.inflate(layoutInflater)
    setContentView(binding.root)
}
© www.soinside.com 2019 - 2024. All rights reserved.