【问题标题】:Out-projected type prohibits the use of method外投影类型禁止使用方法
【发布时间】:2018-06-26 18:04:58
【问题描述】:

我似乎无法理解 Kotlin 泛型,请帮助

我阅读了herehere,但我仍然无法确定如何完成这项工作。我有一个 RecyclerView 适配器,它使用抽象的父 BaseFieldVH 作为 ViewHolder 类。

所以适配器类看起来像这样:

class MyAdapter() : RecyclerView.Adapter<BaseFieldVH<*>>() {
... 
    override fun onBindViewHolder(holder: BaseFieldVH<*>, position: Int) {
        holder.bind(data[position])
    }
}

ViewHolder 实现如下所示:

abstract class BaseFieldVH<in FF : BaseFormField>
    (itemView: View) : RecyclerView.ViewHolder(itemView) {
    ...
    abstract fun bind(formField: FF)
}

但对holder.bind(data[position]) 的实际调用显示错误:

Out-projected type 'BaseFieldVH<*>' prohibits the use of 'public 
abstract fun bind(formField: FF): Unit defined in ...

无用?

我也尝试使用BaseFieldVH&lt;in Nothing&gt; 定义适配器,但随后我尝试将 Nothing 放入需要 BaseFormField 的函数中时收到类型不匹配错误。

使用 BaseFormField

使用BaseFieldVH&lt;iBaseFormField&gt; 定义适配器实际上解决了绑定问题,但是在 onCreateViewHolder 中存在视图持有者的类型不匹配:

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseFieldVH<BaseFormField> {
    val itemView: View
    when (viewType) {
        HEADER_TYPE -> {
            itemView = LayoutInflater.from(parent.context)
                    .inflate(R.layout.item_header, parent, false)
            return HeaderVH(itemView)
        }

HeaderVH 是 BaseFieldVH 的扩展,所以存在类型不匹配

【问题讨论】:

  • 我也处理过 Kotlin 泛型复杂性,感觉肮脏/hacky 的方式是用 java 编写逻辑,然后将其转换为 Kotlin :grimacing: 。否则,这只是挖掘 Kotlin 文档的问题
  • 感谢@ElliotM 的建议。我试过你的技术——它没有用,现在我觉得很脏;)。 kotlin 转换产生以下结果:class MyAdapter(): RecyclerView.Adapter&lt;*&gt;() 和 Android Studio 警告我projections are not allowed for immediate arguments of a supertype。所以我正在查看here,我会尽快回复您。

标签: android generics kotlin


【解决方案1】:

看起来这个问题的答案是你不能实现一个 ViewHolder 类来指定一个泛型的绑定。我猜这是因为 RecyclerView.Adapter 是写的在 Java 中,任何 Kotlin 扩展都过于严格而无法正确实现。

如果你能反驳这个结论,请告诉我!

我发现this 的帖子以我能理解的方式解释了整个投影概念。

最后我放弃了为 ViewHolder 控制类型的尝试:

abstract class BaseFieldVH
  (itemView: View) : RecyclerView.ViewHolder(itemView) {
  ...
  abstract fun bind(formField: Any)
}

这意味着 BaseFieldVH 的每个子类都必须在其绑定函数中进行一些类型检查。例如:

class HeaderVH
  (itemView: View) : BaseFieldVH(itemView) {
...
  override fun bind(headerField: Any) {
    if (headerField is HeaderField) {
      // do something
    }
}

}

但现在至少我没有收到任何错误。

【讨论】:

    【解决方案2】:

    如果您在数据列表中有多个复杂对象(为了在回收站视图中显示不同的项目),您还需要指定您的持有者。

    这里的想法是您提供 Adapter,而不是 Holder 来决定您需要如何处理每种对象类型。

    class MyAdapter() : RecyclerView.Adapter<BaseFieldVH<*>>() {
        ... 
    
        override fun onBindViewHolder(holder: BaseFieldVH<*>, position: Int) {
            val item = data[position]
    
            holder as BaseFieldVH<DATA_ITEM_TYPE>
            item as DATA_ITEM_TYPE
    
            holder.bind(item)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-04-05
      • 1970-01-01
      • 2013-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多