По-моему, второй вариант смотрится тоже не особо красиво
Ребят, ну надо понимать что в статье используется максимально упрощенная модель. Все описано в одном классе, используется enum и т.д. Это сделано умышленно для упрощения восприятия идеи. Как вы реализуете эту идею — уже другой вопрос.
Вот как выглядит моя боевая реализация:
Вариант боевой реализации идеи
public class UsersArbitraryCellAdapter extends ArbitraryCellAdapter {
public UsersArbitraryCellAdapter() {
this.arbitraryCellSelector.addCell(new ProgressArbitraryCell());
this.arbitraryCellSelector.addCell(new AdArbitraryCell());
this.arbitraryCellSelector.addCell(new UserArbitraryCell());
}
public void setUsers(List<UserVo> userList) {
// Set users, ads, progress...
}
}
public abstract class ArbitraryCellAdapter
extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
protected ArbitraryCellSelector arbitraryCellSelector = new ArbitraryCellSelector();
protected List itemList = new ArrayList();
@Override
public final int getItemViewType(int position) {
return arbitraryCellSelector.getCell(itemList.get(position)).type();
}
@Override
public final RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return arbitraryCellSelector.getCell(viewType).holder(parent);
}
@Override
public final void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Object item = itemList.get(position);
arbitraryCellSelector.getCell(item).bind(holder, item);
}
@Override
public final int getItemCount() {
return itemList.size();
}
}
public abstract class ArbitraryCellHolder<T> extends RecyclerView.ViewHolder {
public ArbitraryCellHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
public abstract void bind(T item);
}
public final class ArbitraryCellSelector {
private List<Cell> cellList = new ArrayList<>();
public void addCell(Cell cell) {
cellList.add(cell);
}
public void removeCell(Cell cell) {
cellList.remove(cell);
}
public Cell getCell(Object item) {
for (Cell cell : cellList) {
if (cell.is(item)) {
return cell;
}
}
throw new NoSuchRecyclerRowException();
}
public Cell getCell(int viewType) {
for (Cell cell : cellList) {
if (cell.type() == viewType) {
return cell;
}
}
throw new NoSuchRecyclerRowException();
}
public interface Cell {
boolean is(Object item);
int type();
RecyclerView.ViewHolder holder(ViewGroup parent);
void bind(RecyclerView.ViewHolder holder, Object item);
}
}
public class AdArbitraryCell implements ArbitraryCellSelector.Cell {
@Override
public boolean is(Object item) {
return item instanceof AdVo;
}
@Override
public int type() {
return R.layout.cell_ad;
}
@Override
public RecyclerView.ViewHolder holder(ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.cell_ad, parent, false);
return new AdViewHolder(view);
}
@Override
public void bind(RecyclerView.ViewHolder holder, Object item) {
try {
AdViewHolder adViewHolder = (AdViewHolder) holder;
AdVo ad = (AdVo) item;
adViewHolder.bind(ad);
} catch (ClassCastException e) {
L.printStackTrace(e);
}
}
protected class AdViewHolder extends ArbitraryCellHolder<AdVo> {
@BindView(R.id.ad_text_view)
protected TextView adTextView;
public AdViewHolder(View itemView) {
super(itemView);
}
@Override
public void bind(AdVo item) {
adTextView.setText(item.getTitle());
itemView.setOnClickListener(view -> adPublishSubject.onNext(item));
}
}
}
// Other ArbitraryCells...
Про Adapter Delegates автор не слышал?
Действительно не слышал. Как и многие другие, исходя из моего немалого опыта и оценки статьи сообществом.
Решение изящное, признаю. Что использовать у себя в проекте — импортировать библиотеку или написать один вспомогательный класс ArbitraryCellSelector — дело личного каждого.
В идеале от класса CellType нужно избавляться. Точнее заменять его на не статичный объект. Не секрет, что enum в Java является статичным объектом, а статика может в определенных ситуациях стать головной болью и причиной падений.
В статье enum использован для упрощения материала и простоты восприятия идеи. С этой же цель явно прописаны все методы в контракте enum и локальные переменные.
Все правильно, именно такой подход позволяет избавиться от проверок на тип и преобразований типов. И это самый очевидный подход для решения этой задачи.
Но как вы правильно заметили, у этого подхода есть один недостаток. Под каждый адаптер нам потребуется столько классов-оберток, сколько разнотипных ячеек планируется использовать. Плюс под каждый такой адаптер (а точнее для классов-оберток под текущий адаптер) в идеале создается еще и интерфейс.
Плюс только лишь оборачивание не решает всех поставленных вопросов.
Я сторонник «тонких» моделей. Т.е. модель здесь понимается в самом узком смысле — это просто DataObject. И вся его обязанность сводится к тому, чтобы предоставлять нам доступ к данным. Если обязать этот объект заниматься обработкой самого себя, то это уже будет нарушением принципа SRP.
Но такой подход возможен. И даже может позволить избежать проверок на тип и приведений типов.
Ребят, ну надо понимать что в статье используется максимально упрощенная модель. Все описано в одном классе, используется enum и т.д. Это сделано умышленно для упрощения восприятия идеи. Как вы реализуете эту идею — уже другой вопрос.
Вот как выглядит моя боевая реализация:
Действительно не слышал. Как и многие другие, исходя из моего немалого опыта и оценки статьи сообществом.
Решение изящное, признаю. Что использовать у себя в проекте — импортировать библиотеку или написать один вспомогательный класс ArbitraryCellSelector — дело личного каждого.
В боевых условиях именно так и делается :)
Цель статьи — максимально просто и доступно донести идею. А как вы это реализуете под себя — вопрос десятый.
В статье enum использован для упрощения материала и простоты восприятия идеи. С этой же цель явно прописаны все методы в контракте enum и локальные переменные.
Но как вы правильно заметили, у этого подхода есть один недостаток. Под каждый адаптер нам потребуется столько классов-оберток, сколько разнотипных ячеек планируется использовать. Плюс под каждый такой адаптер (а точнее для классов-оберток под текущий адаптер) в идеале создается еще и интерфейс.
Плюс только лишь оборачивание не решает всех поставленных вопросов.
Но такой подход возможен. И даже может позволить избежать проверок на тип и приведений типов.