我正在尝试找出在Kotlin中进行Android View Binding的最佳方法。似乎有一些选择:
findViewById
val button: Button by lazy { findViewById<Button>(R.id.button) }
Butterknife
https://github.com/JakeWharton/butterknife
@BindView(R.id.button) lateinit var button: Button
Kotlin Android Extensions
https://kotlinlang.org/docs/tutorials/android-plugin.html
import kotlinx.android.synthetic.main.activity_main.*
我对java版本中的findViewById和Butterknife非常熟悉,但Kotlin中每种视图绑定方法的优缺点是什么?
Kotlin Android Extensions能否与RecyclerView + ViewHolder模式配合使用?
Kotlin Android Extensions如何通过include
处理嵌套视图的视图绑定?
例如:对于使用activity_main.xml
的活动,如何访问View custom1
?
activity_main.xml中
<...>
<include layout="@layout/custom" android:id="@+id/custom" />
</>
custom.xml
<...>
<View android:id="@+id/custom1" ... />
<View android:id="@+id/custom2" ... />
</>
答案 0 :(得分:12)
kotlin-android-extensions
更适合Kotlin
。 ButterKnife也很好,但kotlin-android-extensions
是一个更好,更明智的选择。
原因:Kotlin
使用synthetic
属性,并使用caching function
按需调用这些属性(因此,轻微的快速活动/片段加载){{1} } ButterKnife
上一次绑定所有视图(消耗更多时间)。使用ButterKnife.bind()
,您甚至不需要使用注释来绑定视图。
是的,它也适用于RecyclerView + ViewHolder模式,您只需要导入Kotlin
(如果kotlinx.android.synthetic.main.layout_main.view.*
是活动/片段布局文件名)。
您无需为使用layout_main.xml
导入的布局做任何额外的工作。只需使用导入视图的ID。
请查看以下官方文档说明:
Kotlin Android Extensions是Kotlin编译器的一个插件,它做了两件事:
- 在每个Kotlin活动中添加隐藏的缓存功能和字段。该方法非常小,因此不会增加APK的大小。
- 醇>
使用函数调用替换每个合成属性调用。
这是如何工作的,当调用合成属性时,接收器是模块源中的Kotlin Activity / Fragment类,调用缓存函数。例如,给定
include
在MyActivity中生成隐藏的缓存功能,因此我们可以使用缓存机制。
但是在以下情况中:
class MyActivity : Activity()
fun MyActivity.a() {
this.textView.setText(“”)
}
我们不知道是否仅在来自我们的来源的活动或普通Java活动上调用此函数。因此,我们不在那里使用缓存,即使上一个示例中的MyActivity实例是接收器。
链接到上面的documentation page
我希望它有所帮助。
答案 1 :(得分:4)
我不能将此问题标记为重复,因为您要求在不同问题下回答/讨论过多个问题。
Kotlin中每种视图绑定方法的优缺点是什么?
已经讨论过here。
Kotlin Android Extensions如何通过include处理嵌套视图的视图绑定?例如:对于使用activity_main.xml的Activity,如何访问View custom1?
所有Kotlin Android Extensions都会为您致电findViewById
。请参阅here。
Kotlin Android Extensions能否与RecyclerView + ViewHolder模式配合使用?
是的,确实如此。但是,您必须使用将从中获取的视图保存到属性中,因为它们没有像“活动”或“片段”中那样的缓存。请参阅here。
如果您仍有未回答的问题,请随时要求澄清。
答案 2 :(得分:4)
注意使用
val button: Button by lazy { findViewById<Button>(R.id.button) }
当视图被破坏时,我已经面对这个问题了,并且当你的片段实例存活下来时(我认为在活动的情况下它不适用),他们持有 lazy 属性引用旧观点。
示例:
布局中有静态值,比如android:text="foo"
//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"
}
然后片段被破坏,因为你替换了它,但是然后你又回来了,它再次重新激活了onCreateView。
//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"
}
答案 3 :(得分:2)
有很多方法可以在Android中访问视图。快速概述:
我的建议是:
另请参阅:https://www.youtube.com/watch?v=Qxj2eBmXLHg
有趣的是,Jake Wharton(ButterKnife的原始作者)现已加入Google并从事ViewBinding的工作。
答案 4 :(得分:1)
现在有一个第四个选项,称为 View Binding ,可与Android Studio 3.6 Carnary 11一起使用
引用docs.
查看绑定
视图绑定是一项功能,可让您更轻松地编写代码 与视图互动。在模块中启用视图绑定后, 它为存在的每个XML布局文件生成一个绑定类 模块。绑定类的实例包含对以下内容的直接引用 在相应布局中具有ID的所有视图。
在大多数情况下,视图绑定会替换
findViewById
。
与
的区别findViewById
与使用findViewById相比,视图绑定具有重要的优势:
空安全性:由于视图绑定会创建对视图的直接引用,因此不会存在由于无效而导致空指针异常的风险 查看ID。此外,当视图仅存在于某些视图中时 布局的配置,该字段在 绑定类标记为
@Nullable
。类型安全性::每个绑定类中的字段具有与其在XML文件中引用的视图匹配的类型。这意味着 没有类强制转换异常的风险。
与数据绑定库的区别
视图绑定和数据绑定库都生成绑定 您可以用来直接引用视图的类。但是,那里 明显的区别:
- 数据绑定库仅处理使用
<layout>
标签创建的数据绑定布局。- 视图绑定不支持布局变量或布局表达式,因此不能用于将布局与XML数据绑定。
用法
要在项目模块中利用View绑定,请添加 其
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) }
答案 5 :(得分:0)
(如果使用datainding库)。您应该对视图绑定进行数据绑定。
因为它比kotlin扩展名更明确
p.s的findviewbyid非常不便,并提供样板代码