ViewHolder 中的 kotlin-android-extensions

Posted

技术标签:

【中文标题】ViewHolder 中的 kotlin-android-extensions【英文标题】:kotlin-android-extensions in ViewHolder 【发布时间】:2018-02-07 15:49:07 【问题描述】:
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) 

       fun bindata(text: SingleText)
            itemView.title.text = text.title
            itemView.desc.text = text.desc
       

像这段代码一样,Kotlin 在 android-extensions 中有缓存吗?

当我反编译 kotlin 字节码时

public final void bindata(@NotNull SingleText text) 

  Intrinsics.checkParameterIsNotNull(text, "text");
  ((AppCompatTextView)this.itemView.findViewById(id.title)).setText((CharSequence)text.getTitle());
  ((AppCompatTextView)this.itemView.findViewById(id.desc)).setText((CharSequence)text.getDesc());


这意味着当我在Adapter.onBindViewHolder()中调用binData时,每次都会调用findViewById

这显着增加了性能的损失,并没有达到布局复用的目的

Kotlin 在带有 ViewHolder 的 android-extensions 中有任何缓存逻辑吗?

【问题讨论】:

findViewById 找到已创建的视图。所以这意味着你正在重用它。没有您所说的性能问题。 【参考方案1】:

ViewHolder 或任何自定义类中的视图缓存只能来自 Kotlin 1.1.4,并且目前处于实验阶段。

    在根级 build.gradle 文件中更新 Kotlin 版本

classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.4-3"

    在您的应用程序中添加这些行build.gradle

androidExtensions experimental = true

    LayoutContainer 继承您的ViewHolder 类。 LayoutContainerkotlinx.android.extensions 包中的一个接口。

    添加以下导入,其中view_item 是布局名称。

import kotlinx.android.synthetic.main.view_item.* import kotlinx.android.synthetic.main.view_item.view.*

整个ViewHolder 类看起来像:

class ViewHolder(override val containerView: View) : RecyclerView.ViewHolder(containerView),
        LayoutContainer 

    fun bind(title: String) 
        itemTitle.text = "Hello Kotlin!" // itemTitle is the id of the TextView in the layout 
    

反编译的 Java 代码显示该类对视图使用缓存:

    public final void bind(@NotNull String title) 
          Intrinsics.checkParameterIsNotNull(title, "title");
          ((TextView)this._$_findCachedViewById(id.itemTitle)).setText((CharSequence)"Hello Kotlin!");
    

进一步阅读:KEEP proposal、an awesome tutorial。

【讨论】:

【参考方案2】:

据我了解,kotlin-android-extensions 只是一个静态导入的扩展(生成的代码)来替换 View.findViewById。

我建议您将引用存储在您的视图持有者中。

class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) 
   val title: TextView = itemView.title
   val desc: TextView = itemView.desc

   fun bindata(text: SingleText)
       title.text = text.title
       desc.text = text.desc
   

这种方法的一个好处是任何类型不匹配都会在编译时被发现!

【讨论】:

如果为每个View添加一行代码,还不如不使用Kotlin Android扩展。如果将 findViewById() 包装在扩展函数中,它也将是类型安全的。 val title = itemView.find<TextView>(R.id.title) @FrankHarper 如果R.id.title 没有指向TextView,假设指向ImageView。 itemView.find<TextView>(R.id.title) 仍会编译并会导致运行时崩溃,而使用 Kotlin Android 扩展会在编译时抛出错误。【参考方案3】:

在你的项目中:-

 buildscript 
        ext.kotlin_version = '1.2.41'

        repositories 
            google()
            jcenter()
        

在你的应用程序中:

apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android 
dependencies 
  compile "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

在这些之后你可以在你的活动中使用:

import kotlinx.android.synthetic.main.unit_preferences_activity.*

和:

  private fun setClickListener() 
            rlCaloriesBurnt.setOnClickListener
                launchActivity(CaloriesBurntPrefreenceUnit::class.java)
            

            rlDistanceTravelled.setOnClickListener

           tvDistanceUnit.text=resources.getString(R.string.km)

                launchActivity(DistanceTravelledUnit::class.java)
            

            rlWaterConsumption.setOnClickListener
                launchActivity(WaterPreferenceUnit::class.java)
            
            backArrow.setOnClickListener
                finish()
            

        

【讨论】:

以上是关于ViewHolder 中的 kotlin-android-extensions的主要内容,如果未能解决你的问题,请参考以下文章

ViewHolder 中的嵌套 RecyclerView 破坏了折叠工具栏布局

ViewHolder 中的 onClick 无权访问适配器中的单击项目

DataBinding:如何使用 Kotlin 中的泛型创建具有多个 ViewHolder(多个布局)的 Recyclerview

recyclerview viewholder布局中的更改约束 - android

交换列表中的项目后自定义列表适配器和 ViewHolder 模式出现问题

listview的ViewHolder优化