Преобразование универсального адаптера RecyclerView в Kotlin - PullRequest
0 голосов
/ 28 июня 2018

В настоящее время у меня есть список, который я хочу заполнить, но элементы списка могут иметь разные данные. У меня есть два класса данных и, чтобы приспособить это для RecyclerView, у меня есть два разных ViewHolder, расширяющих базовый базовый ViewHolder. Различные ViewHolders требуются, поскольку для разных классов данных используются разные макеты.

Я преобразовал держатели просмотра в Kotlin, однако у меня возникла проблема с адаптером.

База ViewHolder в Котлине:

abstract class BaseViewHolder<T> internal constructor(view: View) : RecyclerView.ViewHolder(view) {
    abstract fun bind(item: T)
}

ViewHolder, который реализует базовый ViewHolder в Kotlin:

class StandardViewHolder(view: View): BaseViewHolder<Standard>(view) {

    private val _eventView      : TextView = view.findViewById(R.id.eventTextView)
    private val _dateView       : TextView = view.findViewById(R.id.dateTextView)

    override fun bind(item: Standard) {
        _eventView.text     = item.event
        _dateView.text      = item.date.toString()
    }
}

В Java я могу создать адаптер, который использует следующие ViewHolders:

public class ListAdapter extends RecyclerView.Adapter<BaseViewHolder> {

    private List<Object> _items;
    private Context _context;

    public ListAdapter(List<Object> items, Context context){
        _items      = items;
        _context    = context;
    }

    @NonNull
    @Override
    public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if(viewType == R.layout.item_standard){
            return new StandardViewHolder(LayoutInflater.from(_context).inflate(
                    R.layout.item_standard, parent, false));
        }

        return new AdvancedViewHolder(LayoutInflater.from(_context).inflate(
                R.layout.item_advanced, parent, false));
    }

    @Override
    @SuppressWarnings("unchecked")
    public void onBindViewHolder(@NonNull BaseViewHolder holder, int position) {
        holder.bind(_items.get(position));
    }

    @Override
    public int getItemCount() {
        return _items.size();
    }

    @Override
    public int getItemViewType(int position) {
        if(_items.get(position) instanceof Standard){
            return R.layout.item_standard;
        }

        return R.layout.item_advanced;
    }
}

Однако, если я преобразую это в Kotlin, я получаю сообщение об ошибке на holder.bind , которое равно:

Запроектированный тип «BaseViewHolder <*>» запрещает использование «public». абстрактная забавная привязка (предмет: T) '

class ListAdapter(private val _items: List<Any>, private val _context: Context) : RecyclerView.Adapter<BaseViewHolder<*>>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*> {
        return if (viewType == R.layout.item_standard) {
            StandardViewHolder(LayoutInflater.from(_context).inflate(
                    R.layout.item_standard, parent, false))
        } else {
            AdvancedViewHolder(LayoutInflater.from(_context).inflate(
                    R.layout.item_advanced, parent, false))
        }
    }

    override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) = holder.bind(_items[position])

    override fun getItemCount() = _items.size

    override fun getItemViewType(position: Int): Int {
        return if (_items[position] is Standard) {
            R.layout.item_standard
        } else {
            R.layout.item_advanced
        }
    }
}

Как использовать эти общие ViewHolders в Kotlin?

1 Ответ

0 голосов
/ 30 июня 2018

Проблема в том, что, хотя вы знаете, что привязываемый элемент соответствует типу ViewHolder, который был создан для него, вы не можете доказать это во время компиляции, поэтому компилятор кричит на вас. Вы не можете вызвать bind на BaseViewHolder<*>, потому что тогда аргумент должен иметь тип *, что не может произойти. Что вам нужно там BaseViewHolder<Any>, но вы не можете сделать адаптер RecyclerView.Adapter<BaseViewHolder<Any>>, потому что это сломает onCreateViewHolder. И я попробовал BaseViewHolder<out Any>, это тоже не работает.

Итак, вот что вы делаете: используйте BaseViewHolder<*>, но затем внутри onBindViewHolder приведите его к BaseViewHolder<Any>. Компилятор будет жаловаться « Эй! class ListAdapter( private val _items: List<Any>, private val _context: Context ) : RecyclerView.Adapter<BaseViewHolder<*>>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*> { return if (viewType == R.layout.item_standard) { StandardViewHolder(LayoutInflater.from(_context).inflate( R.layout.item_standard, parent, false)) } else { AdvancedViewHolder(LayoutInflater.from(_context).inflate( R.layout.item_advanced, parent, false)) } } @Suppress("UNCHECKED_CAST") override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) { (holder as BaseViewHolder<Any>).bind(_items[position]) } override fun getItemCount() = _items.size override fun getItemViewType(position: Int): Int { return if (_items[position] is Standard) { R.layout.item_standard } else { R.layout.item_advanced } } }

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