Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/232.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 将类传递给Kotlin函数以在适配器中创建ViewHolder_Android_Generics_Kotlin - Fatal编程技术网

Android 将类传递给Kotlin函数以在适配器中创建ViewHolder

Android 将类传递给Kotlin函数以在适配器中创建ViewHolder,android,generics,kotlin,Android,Generics,Kotlin,我有一个抽象类: abstract class AbstractViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) 还有几个孩子: class LabelViewHolder(itemView: View) : AbstractViewHolder(itemView) { val name: TextView = itemView.label } class ButtonViewHolder(itemView:

我有一个抽象类:

abstract class AbstractViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
还有几个孩子:

class LabelViewHolder(itemView: View) : AbstractViewHolder(itemView) {
    val name: TextView = itemView.label
}

class ButtonViewHolder(itemView: View) : AbstractViewHolder(itemView) {
    val name: TextView = itemView.button
}
在onCreateViewHolder中,我希望在以下情况下绕过所有视图类型:

为了避免为许多when分支编写相同的代码,我想使用如下函数:

return when (viewType) {
    ViewType.LABEL.id -> getNewViewHolder(viewGroup, R.layout.row_label, LabelViewHolder::class.java)
    ViewType.BUTTON.id -> getNewViewHolder(viewGroup, R.layout.row_button, ButtonViewHolder::class.java)
}

private fun getNewViewHolder(viewGroup: ViewGroup, @LayoutRes layoutRes: Int, cls: Class<out AbstractViewHolder>): AbstractViewHolder {
    val view = LayoutInflater.from(viewGroup.context).inflate(layoutRes, viewGroup, false)
    return cls.newInstance() // cls(view) is not allowed.
}

如您所见,我无法返回AbstractViewHolder子对象,因为它不允许我创建带有参数view的类。是否可以将类传递给函数并创建其对象?

使用泛型具体化参数生成函数。像这样:

private inline fun <reified T> create(parent: ViewGroup, @LayoutRes layoutRes: Int): T {
    return T::class.java.constructors[0].newInstance(
            LayoutInflater.from(parent.context).inflate(layoutRes, parent, false)
    ) as T
}
然后

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AbstractViewHolder {
    return when (viewType) {
        0 -> create<LabelViewHolder>(parent, R.layout.abc_search_view)
        else -> create<ButtonViewHolder>(parent, R.layout.abc_action_menu_item_layout)
    }
}
现在您可以访问T java对象并调用propert constructor。 这应该可以在调试中使用,对于发布版,请记住确保proguard不会删除您使用的构造函数。

请参阅


我在这里遇到了一个问题。在发布版本中,我们无法使用反射并获取异常:java.lang.ArrayIndexOutOfBoundsException:length=0;索引=0。所以,如果我们想使用这段代码,我们应该在proguard-rules.pro中添加所有创建的viewholder:-keepattributes Signature、innerClass、EnclosingMethod和更高版本:-为所有viewholder保留class com.package.presentation.YourAdapter$ButtonViewHolder{*;}等等。我现在可以试试,但也许不要混淆从某个AbstractViewHolder继承的所有类。或者使用注释@dontobfuscate,我相信这是可能的,它可以帮助您。虽然我回来创建了几个类似的类,但应该是我不能,我不认为今天,我也不能编辑最后的评论xD对不起。无论如何,让我知道它是否有效;
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AbstractViewHolder {
    return when (viewType) {
        0 -> create<LabelViewHolder>(parent, R.layout.abc_search_view)
        else -> create<ButtonViewHolder>(parent, R.layout.abc_action_menu_item_layout)
    }
}
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): AbstractViewHolder {
    return when (viewType) {
        LABEL -> createItem(viewGroup, R.layout.row_label, ::LabelViewHolder)
        BUTTON -> createItem(viewGroup, R.layout.row_button, ::ButtonViewHolder)
        else -> throw IllegalStateException("Wrong class")
    }
}

private fun <T> createItem(
    viewGroup: ViewGroup,
    layoutRes: Int,
    method: (View) -> T
): T {
    val view = LayoutInflater.from(viewGroup.context).inflate(layoutRes, viewGroup, false)
    return method(view) // Creates T(view).
}