Проблема с Kotlin Общими параметрами в ListAdapter - PullRequest
0 голосов
/ 09 апреля 2020

Я пытаюсь исправить Generi c ListAdapter для RecyclerView. У меня есть 3 вещи, которые я хочу передать в адаптер. Список элементов, макет строки для использования и ViewHolder. Я могу получить список и макет, но это ViewHolder. Вот что у меня есть, но я все еще новичок в Generics в Kotlin. Я попытался использовать метод Class out, а затем у меня возникли проблемы с вызовом конструктора для определенного c видоискателя.

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
}

1 Ответ

1 голос
/ 09 апреля 2020

Вы можете сделать это, взяв конструктор ViewHolder вместо класса. Таким образом, вам не придется использовать отражение для создания экземпляра ViewHolder. Для ViewHolder должен быть тип generic c, чтобы ваши подклассы могли правильно реализовать onBindViewHolder и иметь доступ к указанному типу c 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. И теперь вам нужно быть осторожным, чтобы передать правильный макет, который соответствует указанному типу c ViewHolder. Вы также можете удалить этот параметр и выполнить макет в конструкторе ViewHolder, чтобы избежать этой проблемы. Но теперь все, что вы сделали, это переместили функциональность onCreateViewHolder в блок init вашего ViewHolder.

Кроме того, ваша версия абстрактного класса подрывает ожидаемые результаты переопределенных функций. Почему каждый элемент в списке имеет свой тип? Почему идентификаторы товара основаны на позиции в списке? Это только портит функциональность для редактирования данных списка (перестановка, добавление и удаление будут нарушены).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...