Evil Mouth's Blog

Kotlin androidExtensions findViewById缓存问题

September 26, 2019

Kotlin Android Extensions用的肯定很爽,少了一堆findViewById的编写,插件本身为我们生成代码,并且还会缓存起来,通过调用_$_findCachedViewById代替,避免频繁调用findViewById,看起来方便又高效,实际上有一个需要注意的点被忽略

0x01 缓存问题

在实际项目中,往往不止在ActivityFragment里面用到该插件,更多的会是在列表里面的item去使用,比方说RecyclerViewViewHolder,往往只是这样写

holder.itemView.textView1.text = "text1"
holder.itemView.textView2.text = "text2"

看上去跟Activity调用的方式差不多,只是需要通过具体的itemView去访问到具体的textView1,应该没什么问题,但是当把 kotlin 代码转成 Java 代码后,看到的是这样的情况

TextView var24 = (TextView)var3.findViewById(id.textView1);
var24.setText("text1")

可以看到并没有使用 cache,也就是_$_findCachedViewById,当我改成调用两次

holder.itemView.textView1.text = "text1"
holder.itemView.textView1.textSize = 16f

则会

TextView var24 = (TextView)var3.findViewById(id.textView1);
var24.setText("text1")
var24 = (TextView)var3.findViewById(id.textView1);
var24.setTextSize(14f)

竟然调用了两次findViewById

0x02 缓存问题解决

当在这种需要通过view去获取子view再去操作的情况下,官方其实后来给了一个解决方案

  • LayoutContainer

需要额外再build.gradle配置

androidExtensions {
    experimental = true
}

然后将需要的类实现LayoutContainer接口

class ViewHolder(override val containerView: View) : RecyclerView.ViewHolder(containerView), LayoutContainer {
    fun setup() {
        textView1.text = "text1"
        textView1.textSize = 16f
    }
}

这下再来看看编译后的代码

TextView var24 = (TextView)this._$_findCachedViewById(id.textView1);
var24.setText("text1")
var24 = (TextView)this._$_findCachedViewById(id.textView1);
var24.setTextSize(14f)

0x03 待续

— Evil Mouth