【问题标题】:Can I defer the view binding in an adapter using Kotlin Android Extension我可以使用 Kotlin Android 扩展推迟适配器中的视图绑定吗
【发布时间】:2017-12-26 10:27:11
【问题描述】:

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)

}

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

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

编辑:关于“缓存”问题的详细信息。

在活动中使用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 的范围?

【问题讨论】:

  • 您可以将所有 View 引用保存在 holder 类中,并仅在 init 块中调用 findViewById
  • 请考虑更新您的问题以反映给定的歧义。还要添加实例化适配器的用例。或许我稍后会找到答案……
  • @tynn 是的。检查更新。感谢您的宝贵时间!

标签: android kotlin kotlin-android-extensions


【解决方案1】:

你可以这样使用:

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

它会反编译成这样:

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

【讨论】:

    【解决方案2】:

    灵感来自@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);
    

    这正是我想要的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-03
      • 1970-01-01
      • 1970-01-01
      • 2022-07-03
      • 1970-01-01
      • 1970-01-01
      • 2012-03-27
      相关资源
      最近更新 更多