我正在尝试使用通用基本 View 持有者在回收器 View 中实现多种 View 类型。
BaseViewHolder 类是
abstract class BaseViewHolder<T>(itemView: View) : RecyclerView.ViewHolder(itemView) {
abstract fun bind(item: T)
}
然后我为特定 View 类型创建了一个 View 持有者类
inner class CarouselViewHolder(itemView: View) : BaseViewHolder<HomeCarousel>(itemView) {
override fun bind(item: HomeCarousel) {
}
}
从 fun onBindViewHolder 方法访问此绑定(bind)函数时出现错误。
投影类型“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)
}
最佳答案
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<HomeCarousel>
不再是 BaseViewHolder<Any>
的子类型,因为子类型是相反的。
为了解决这个问题,我们可以进行“不安全转换”,就像我在代码中所做的那样。
哦,还有使用BaseViewHolder<*>
(star-projection) 确实解决了子类型问题,因为 BaseViewHolder 的每个实例现在都是子类型,但它施加了协变和逆变的限制,因此在这里没有用。
关于android - RecyclerView 具有多种 View 类型和泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56988188/