Мне нравится ответ @ TheWanderer, но я хотел добавить еще один, чтобы выделить то, что, как мне кажется, облегчит вашу жизнь.
В отличие от ListView
, RecyclerView
не волнует, какие ценности вывозврат от getItemViewType()
;пока вы возвращаете различные значения из этого метода, RecyclerView
счастлив.Это позволяет вам использовать идентификаторы ресурсов макета в качестве возвращаемых значений, что означает, что вам никогда не придется определять свои собственные константы!
@Override
public int getItemViewType(int position) {
Object obj = callSMSFeed.get(position);
if (obj instanceof Phonecall) {
return R.layout.cardview_a;
} else if (obj instanceof SMSmessage) {
return R.layout.cardview_b;
}
throw new IllegalStateException("item at position " + position + " is not a Phonecall or SMSmessage: " + obj);
}
Здесь мы возвращаем R.layout.cardview_a
вместо TYPE_EXPANDABLE
;оба находятся под капотом int
, но теперь мы можем позволить структуре ресурсов позаботиться о том, чтобы определить их для нас.
Мы также выдаем исключение, если когда-нибудь попадем в Object
, который не являетсяPhonecall
или SMSmessage
, чтобы мы сразу знали, что есть дело, которое нам нужно рассмотреть.Такое исключение следует видеть только разработчикам, совершающим ошибки;приложение никогда не будет зависать от пользователя, потому что вы продолжите и исправите его, прежде чем выпустить приложение.
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View itemView = inflater.inflate(viewType, parent, false);
switch (viewType) {
case R.layout.cardview_a:
return new CallViewHolder(itemView);
case R.layout.cardview_b:
return new SMSViewHolder(itemView);
default:
throw new IllegalArgumentException("unexpected viewType: " + viewType);
}
}
Поскольку мы вернули идентификаторы макетов из getItemViewType()
, у нас нетбеспокоиться о переводе наших собственных констант в значения R.layout
;мы можем просто надуть viewType
напрямую.Нам по-прежнему нужен оператор switch
, чтобы знать, какой тип ViewHolder
должен быть возвращен.
Опять же, мы бросили здесь исключение на случай, если нам когда-нибудь передадут viewType
, которого мы не ожидаем,Этого «не произойдет», но если он когда-либо сделает , будет очень ясно, где проблема, и вам будет легко ее исправить.
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
int viewType = holder.getItemViewType();
switch (viewType) {
case R.layout.cardview_a:
Phonecall call = (Phonecall) callSMSFeed.get(position);
((CallViewHolder) holder).showCallDetails(call);
break;
case R.layout.cardview_b:
SMSmessage sms = (SMSmessage) callSMSFeed.get(position);
((SMSViewHolder) holder).showSmsDetails(sms);
break;
default:
throw new IllegalArgumentException("unexpected viewType: " + viewType);
}
}
Здесь единственная разницазамена ваших констант идентификаторами макета внутри switch
.Ничего страшного.И, конечно, мы терпим крах, если получаем что-то, чего не ожидаем.
Обратите внимание, что я удалил ключевое слово final
из параметров.Хотя компилятор с радостью позволит вам добавить их, вы не должны этого делать.Из-за таких методов, как notifyItemInserted()
, позиция ViewHolder
может меняться с течением времени без повторного связывания.Решение этой проблемы выходит за рамки вашего вопроса, но на это следует обратить внимание.