android - ListAdapter 中的 Kotlin 泛型问题
问题描述
我正在尝试为 RecyclerView 纠正一个通用 ListAdapter。我有 3 件事要传递给适配器。项目列表、要使用的行布局和 ViewHolder。我能够获得一般的列表和布局,但它是 ViewHolder。这是我到目前为止所拥有的,但我对 Kotlin 的泛型仍然很陌生。我尝试使用 Class out 方法,然后在调用特定视图的构造函数时遇到问题。
abstract class AbstractListAdapter(
private val items: List<*>,
private val layoutId: Int,
private val viewHolderClass: ???? >
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(layoutId, parent, false)
return viewHolderClass.??? // need to call the constructor of the specific viewholder passed in
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItemViewType(position: Int): Int {
return position
}
override fun getItemCount(): Int {
return items.size
}
}
// List adapter uses abstract
class ListAdapter(private items: List<Files>, private val id: Int, private viewHolder: FileViewHolder) : AbstractListAdapter(items, id, fileViewHolder) {
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
... some code here for the viewholder and list combining
}
}
// Specific VH that want to pass into abstract generic yet it will call the constructor from there.
class FileViewHolder(fileView: View) {
.... grab views for specific layout
}
解决方案
您可以通过采用 ViewHolder 构造函数而不是类来做到这一点。这样您就不必使用反射来实例化 ViewHolder。您需要拥有 ViewHolder 的泛型类型,以便您的子类可以正确实现onBindViewHolder
并访问特定类型的 ViewHolder。
此外,您必须使items
属性具有类型,否则您将无法使用它。而且您的子类可能需要能够访问它,因此它需要受到保护,而不是私有。
我没有对此进行测试:
abstract class AbstractListAdapter<VH: RecyclerView.ViewHolder> (
protected val items: List<*>,
private val layoutId: Int,
private val viewHolderConstructor: (View) -> VH >
) : RecyclerView.Adapter<VH>(){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(layoutId, parent, false)
return viewHolderConstructor(v)
}
//...
}
然后为了实现它,在超构造函数调用中指定 ViewHolder 构造函数并指定类型。由于指定了类型,因此您不需要在子类中为其提供构造函数参数。
class ListAdapter(private items: List<Files>, private val id: Int) : AbstractListAdapter<FileViewHolder>(items, id, ::FileViewHolder) {
override fun onBindViewHolder(holder: FileViewHolder, position: Int) {
//...
}
}
也就是说,我不确定这实际上为您带来了什么。似乎只是在移动代码。您仍然需要从父视图中提取视图引用。您只需在 ViewHolder 初始化中而不是在onCreateViewHolder
. 现在您必须小心地传递与特定 ViewHolder 类型匹配的正确布局。您也可以删除该参数并在 ViewHolder 构造函数中进行布局以避免该问题。但是现在您所做的只是将onCreateViewHolder
功能移到 ViewHolder 的init
块中。
此外,您的抽象类版本正在颠覆您已覆盖的函数的预期结果。为什么列表中的每个项目都有不同的类型?为什么项目 ID 会基于列表位置?这只会破坏编辑列表数据的功能(重新排列、添加和删除将被破坏)。
推荐阅读
- r - 使用矩阵索引列矩阵时如何理解错误“subscipts out of bound”
- python - python的设置器行为
- string - 如何在 Julia 中创建一个填充有字符串的 CuArray?
- python - Time.Sleep() 正在冻结我的 pygame 窗口并冻结我的函数
- r - 添加具有特定组合的列
- reactjs - 使用 openapi-generator 启用 CORS
- c# - 如何更改 asp.net Core 3 或 Net Core 5 中的默认端口
- google-cloud-platform - 是否可以在 GCP/stackdriver 中创建基于日志的累积指标?
- github - Github Actions 无法写入文件,权限被拒绝(在 docker 容器内)
- flutter - 在 Flutter 中设置父 Widget 的状态