簡體   English   中英

具有泛型的多種視圖類型的RecyclerView

[英]RecyclerView with multiple view types with Generics

我正在嘗試使用通用基本視圖持有者在回收者視圖中實現多種視圖類型。

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 <*>'的類型禁止使用'公共抽象有趣的綁定(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-sitevariance之類的東西。

我認為解決該問題的正確方法是使用逆方差:

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

這是因為類型T的對象可以執行任何操作,並且需要傳遞給setter,因此我們只需要將其設置為ViewHolder。 但是,對立事物有一個有趣的轉折……子類型化現在朝相反的方向起作用! 因此,現在BaseViewHolder<HomeCarousel>不再是BaseViewHolder<Any>的子類型,因為子類型是相反的。

為了解決這個問題,我們可以像代碼中那樣進行“不安全的轉換”。

哦,使用BaseViewHolder<*> (星型投影)確實可以解決子類型問題,因為BaseViewHolder的每個實例現在都是一個子類型,但是它同時限制了協方差和協方差,因此在這里沒有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM