我可以使用 Kotlin Android Extension 延迟适配器中的视图绑定吗

Can I defer the view binding in an adapter using Kotlin Android Extension

Kotlin Android 扩展提供了一种直接在 Activity/fragment/Adapters 中使用 ID 的方法。 所以我想要的是一种通用的适配器方式,并将绑定视图的责任留给适配器的用户而不是适配器本身。 例如:

class GenericAdapter<T>(
    @LayoutRes private val layoutId: Int,
    private var list: List<T>,
    inline private val bind: (View, T, Int) -> Unit) : RecyclerView.Adapter<InnerHolder>() {
    override fun onBindViewHolder(holder: InnerHolder?, position: Int) {
        holder?.containerView?.let {
             bind(holder.containerView, list[position], position)
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): InnerHolder =
        InnerHolder(LayoutInflater.from(parent?.context).inflate(layoutId,
            parent,
            false))

    override fun getItemCount(): Int = list.size

    class InnerHolder(
        val containerView: View?) : RecyclerView.ViewHolder(containerView)

}

我可以根据需要传递布局文件和绑定函数来绑定适配器,而无需为每个带有适配器的布局文件重写相同的代码。

但问题是: 每次 ChildView 膨胀时,ViewHolder 模式都希望消除调用 "findViewById"。但是随着我的适配器的实现。 adapter每次绑定view的时候都需要调用"findViewById"

编辑:"cache" 问题的详细信息。

使用 Activity 中的 GenericAdapter。喜欢

override fun onCreated(savedInstanceState: Bundle?){
    list.adapter = GenericAdapter<Item>(items){ view,item,position ->
        view.textview.text = item.text
    }
}

这将反编译为:

     TextView var2 = (TextView)var10000.findViewById(id.textview);
     Intrinsics.checkExpressionValueIsNotNull(var2, "itemView.tv_text");
     var2.setText((CharSequence)String.valueOf(var1));

但是他们有一个带有 Android 扩展的实验工具,带有 LayoutContainer 例如:

class InnerHolder(
    override val containerView: View?) : RecyclerView.ViewHolder(containerView), LayoutContainer {
    fun bind(int: Int) {
        textview.text = int.toString()
    }
}

这将完美地使用缓存视图:

     TextView var10000 = (TextView)this._$_findCachedViewById(id.tv_text);

但问题是缓存视图需要在LayoutContainer的范围内。例如这个实现不会工作:

class InnerHolder(
    override val containerView: View?) : RecyclerView.ViewHolder(containerView), LayoutContainer {
    fun bind(int: Int) {
        this.bindInt(int)
    }

}
// some extension function outside the ViewHolder Scope. 
fun LayoutContainer.bindInt(int: Int) {
    tv_text.text = int.toString()

}

这仍将使用 findViewById 来查找视图:

  TextView var10000 = (TextView)$receiver.getContainerView().findViewById(id.tv_text);

所以我的问题是有没有办法以某种方式保留缓存并仍然使用我的适配器的 Android 扩展但在 viewholder 的范围之外?

你可以这样使用:

innerHolder.apply {
    tv_text.text = "test"
}

会反编译成这样:

TextView var10000 = (TextView)innerHolder._$_findCachedViewById(id.tv_text);
var10000.setText((CharSequence)"test");

灵感来自@linx

如果我只是为 InnerHolder 而不是 LayoutContainer 创建一个扩展函数。上下文为 Android 扩展提供了足够的信息来获取缓存的视图。

class InnerHolder(
    override val containerView: View?) : RecyclerView.ViewHolder(containerView), LayoutContainer {
    fun bind(int: Int) {
        this.bindInt(int)
    }

}
// some extension function outside the ViewHolder Scope. 
fun InnerHolder.bindInt(int: Int) {
    tv_text.text = int.toString()

}

这将编译成

TextView var10000 = (TextView)$receiver._$_findCachedViewById(id.tv_text);

这正是我想要的。