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

时间:2017-09-29 04:52:12

标签: android kotlin findviewbyid butterknife kotlin-android-extensions

我正在尝试找出在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" ... />
</>

6 个答案:

答案 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编译器的一个插件,它做了两件事:

     
      
  1. 在每个Kotlin活动中添加隐藏的缓存功能和字段。该方法非常小,因此不会增加APK的大小。
  2.   
  3. 使用函数调用替换每个合成属性调用。

         

    这是如何工作的,当调用合成属性时,接收器是模块源中的Kotlin Activity / Fragment类,调用缓存函数。例如,给定

  4.   
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中访问视图。快速概述:

enter image description here

我的建议是:

  1. findViewById:旧学校。避免。
  2. ButterKnife:很老,但是样板更少,并且增加了一些功能。仍然缺乏编译时安全性。尽可能避免。
  3. Kotlin Synthetic:确实是findViewbyId的优雅缓存版本。更好的性能和更少的样板,但仍然没有编译时的安全性。如果不需要编译时安全性的最佳选择。
  4. ViewBinding:介于选项1-3和数据绑定之间的某个位置。但是缺乏 DataBinding的强大功能(例如2种方式的数据绑定以及在XML文件中使用变量)。
  5. 数据绑定:最强大的选项。与LiveData和ViewModels(JetPack)很好地集成在一起,以创建响应式UI(类似于RxJava)。可以减慢大型项目/ UI上的构建时间(像ButterKnife一样使用注释处理器)。我强烈的个人偏好。

另请参阅: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非常不便,并提供样板代码