【问题标题】:RecyclerView with multiple view types with GenericsRecyclerView 具有多种视图类型和泛型
【发布时间】:2019-07-12 15:15:18
【问题描述】:

我正在尝试使用通用基本视图持有者在回收者视图中实现多种视图类型。

BaseViewHolder 类是

abstract class BaseViewHolder<T>(itemView: View) : RecyclerView.ViewHolder(itemView) {
    abstract fun bind(item: T)
}

然后我为特定的视图类型创建了一个视图持有者类

inner class CarouselViewHolder(itemView: View) : BaseViewHolder<HomeCarousel>(itemView) {
    override fun bind(item: HomeCarousel) {
    }
}

从有趣的 onBindViewHolder 方法访问此绑定函数时出现错误。

外投影类型'BaseViewHolder'禁止使用'public abstract fun bind(item:T):

 override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) {
    val element = data[position]
    when (element) {
        is HomeCarousel -> {
            holder.bind(element)
        }
        else -> throw java.lang.IllegalArgumentException("Invalid binding")
    }
}

遇到错误

       holder.bind(element)

这是我的整个适配器类

class HomePageRecylerAdapter(private val data: ArrayList<Any>) : RecyclerView.Adapter<BaseViewHolder<*>>() {

companion object {
    const val typeCarousel = 0
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*> {
    return when (viewType) {
        typeCarousel -> {
            val view =
                LayoutInflater.from(parent.context).inflate(R.layout.recycler_item_home_carasoul, parent, false)
            CarouselViewHolder(view)
        }
        else -> throw IllegalArgumentException("Invalid view type")
    }

}

override fun getItemCount() = data.size

override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) {
    val element = data[position]
    when (element) {
        is HomeCarousel -> {
            holder.bind(element)
        }
        else -> IllegalArgumentException("Invalid binding")
    }
}



override fun getItemViewType(position: Int): Int {
    val element = data[position]
    return when (element) {
        is HomeCarousel -> typeCarousel
        else -> throw IllegalArgumentException("Invalid type of data {$position}")
    }
}
inner class CarouselViewHolder(itemView: View) : BaseViewHolder<HomeCarousel>(itemView) {
    override fun bind(item: HomeCarousel) {
    }
}
}
abstract class BaseViewHolder<T>(itemView: View) : 
RecyclerView.ViewHolder(itemView) {
   abstract fun bind(item: T)
} 

【问题讨论】:

    标签: android kotlin android-recyclerview


    【解决方案1】:

    TLDR;

    嗯,这是一个应该可以工作的代码:

    class HomePageRecylerAdapter(private val data: ArrayList<Any>) : RecyclerView.Adapter<BaseViewHolder<Any>>() {
    
        companion object {
            const val typeCarousel = 0
        }
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<Any> {
            return when (viewType) {
                typeCarousel -> {
                    val view =
                            LayoutInflater.from(parent.context).inflate(0, parent, false)
                    CarouselViewHolder(view) as BaseViewHolder<Any>
                }
                else -> throw IllegalArgumentException("Invalid view type")
            }
    
        }
    
        override fun getItemCount() = data.size
    
        override fun onBindViewHolder(holder: BaseViewHolder<Any>, position: Int) {
            val element = data[position]
            when (element) {
                is HomeCarousel -> {
                    holder.bind(element)
                }
                else -> IllegalArgumentException("Invalid binding")
            }
        }
    
    
    
        override fun getItemViewType(position: Int): Int {
            val element = data[position]
            return when (element) {
                is HomeCarousel -> typeCarousel
                else -> throw IllegalArgumentException("Invalid type of data {$position}")
            }
        }
        inner class CarouselViewHolder(itemView: View) : BaseViewHolder<HomeCarousel>(itemView) {
            override fun bind(item: HomeCarousel) {
            }
        }
    }
    abstract class BaseViewHolder<in T: Any>(itemView: View) :
            RecyclerView.ViewHolder(itemView) {
        abstract fun bind(item: T)
    }
    

    说明

    这个答案可能有助于您获得更多见解 - https://stackoverflow.com/a/51110484/2674983

    虽然,我发现答案中的理由是错误的。问题不在于适配器是用 Java 编写的,而是它需要返回 viewholder 的子类型并将其作为参数传递。否则,使用use-site variance 之类的东西会很容易。

    我认为解决它的正确方法是使用逆变:

    abstract class BaseViewHolder<in T>(itemView: View) :
            RecyclerView.ViewHolder(itemView) {
        abstract fun bind(item: T)
    }
    

    那是因为 T 类型的对象可以是任何东西,它需要传递给一个 setter,所以我们只需要将它设置到 ViewHolder 中。然而,对立式有一个有趣的转折……现在子类型的工作方向相反!所以,现在BaseViewHolder&lt;HomeCarousel&gt; 不再是BaseViewHolder&lt;Any&gt; 的子类型,因为子类型被颠倒了。

    要修复它,我们可以像我在代码中所做的那样进行“不安全的强制转换”。

    哦,使用BaseViewHolder&lt;*&gt;(星形投影)确实解决了子类型问题,因为 BaseViewHolder 的每个实例现在都是子类型,但它同时设置了协变和逆变的限制,因此在这里没有用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-02
      • 1970-01-01
      相关资源
      最近更新 更多