Вот несколько советов, которые могут оказаться полезными:
Не зависит от ViewModel
s в ваших адаптерах.ViewModel
s предназначены для обработки событий из представлений (фрагментов или действий) и передачи обновлений обратно представлениям через некоторый наблюдаемый механизм (чаще всего LiveData
экземпляров).Ссылка на ViewModel
непосредственно внутри адаптера плохая, так как он связывает их вместе.Это означает, что вам будет очень трудно повторно использовать адаптер с другим ViewModel
, если это необходимо.Я знаю, что на данный момент это маловероятно, но просто поверь мне в этом.После применения изменений ваш адаптер должен выглядеть примерно так:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.TaskViewHolder> {
private LayoutInflater mLayoutInflater;
private List<Task> mTasks;
private OnItemClickListener mOnItemClickListener;
public RecyclerViewAdapter(@NonNull Context context, @NonNull List<Task> tasks) {
mLayoutInflater = LayoutInflater.fromContext(context);
mTasks = tasks;
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
mOnItemClickListener = onItemClickListener;
}
@NonNull
@Override
public RecyclerViewAdapter.TaskViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
final RecyclerViewItemBinding binding = DataBindingUtil.inflate(mLayoutInflater, R.layout.recycler_view_item, parent, false);
return new TaskViewHolder(binding);
}
@Override
public void onBindViewHolder(@NonNull final RecyclerViewAdapter.TaskViewHolder holder, final int position) {
Task currentTask = tasks.get(position);
holder.bind(currentTask, mOnItemClickListener);
}
@Override
public int getItemCount() {
return tasks.size();
}
public void setTasks(List<Task> tasks) {
this.tasks = tasks;
notifyDataSetChanged();
}
public Task getTaskPosition(int position) {
return tasks.get(position);
}
public class TaskViewHolder extends RecyclerView.ViewHolder {
private final RecyclerViewItemBinding mBinding;
public TaskViewHolder(RecyclerViewItemBinding binding) {
super(binding.getRoot());
this.mBinding = binding;
}
public void bind (Task item, OnItemClickListener onItemClickListener) {
mBinding.setItem(item);
mBinding.executePendingBindings();
itemView.setOnClickListener(view -> {
if (onItemClickListener != null) {
onItemClickListener.onItemClick(view, item);
}
}
}
}
public interface OnItemClickListener {
void onItemClick(View view, Task item);
}
}
Метод OnItemClickListener.onItemClick()
теперь передает представление и сам элемент в качестве параметров.Это самый простой способ показать выбранный элемент тому, кто может быть заинтересован.Приемник по щелчку не устанавливается на уровне адаптера, используя setOnItemClickListener()
.
. Настройка OnClickListener
представления элемента теперь выполняется в методе bind()
TaskViewHolder
.При связывании мы знаем точный элемент, который будет заполнять представление, поэтому мы можем вернуть его в OnItemClickListener
.
Вы также должны упростить макет, так как есть много вещей, которыена самом деле не нужны.Это может выглядеть так:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="task"
type="com.example.daniellachacz.taskmvvm.model.Task">
</variable>
</data>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="120dp"
android:shadowColor="@color/colorPrimary"
android:backgroundTint="@color/cardview_shadow_end_color">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="110dp"
android:layout_marginBottom="6dp"
android:layout_marginTop="6dp"
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp">
<TextView
android:id="@+id/description_item"
android:layout_width="250dp"
android:layout_height="96dp"
android:layout_marginStart="5dp"
android:layout_marginTop="9dp"
android:layout_marginBottom="5dp"
android:text="@{item.description}"
android:textSize="18sp"
android:textColor="#020202"
android:focusable="true" />
<TextView
android:id="@+id/date_item"
android:layout_width="90dp"
android:layout_height="40dp"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginTop="9dp"
android:layout_marginEnd="10dp"
android:gravity="center"
android:text="@{item.date}"
android:textColor="#020202"
android:textSize="16sp" />
<TextView
android:id="@+id/time_item"
android:layout_width="90dp"
android:layout_height="40dp"
android:layout_alignParentBottom="true"
android:layout_alignStart="@+id/date_item"
android:layout_marginBottom="10dp"
android:layout_marginEnd="10dp"
android:gravity="center"
android:text="@{item.time}"
android:textColor="#020202"
android:textSize="16sp" />
</RelativeLayout>
</android.support.v7.widget.CardView>
</layout>
Единственная переменная - item
, и мы привязываем ее свойства к TextView
s.
Полагаю, этого должно быть достаточно, чтобы вы начали.
Просто пара других вещей, которые не имеют прямого отношения к вопросу, но важны.
- Нулевая безопасность - вы никогда не проверяете вход при вызове
setTask()
в адаптере.Клиент может передать null
и вызвать сбои повсюду.Вы должны попытаться предотвратить это. - Вызов
notifyDataSetChanged()
не является хорошей практикой при работе с RecyclerView.Adapter
, так как это отменит все встроенные анимации RecyclerView
.Лучше использовать другие notify...
методы.Вы можете проверить DiffUtil
в какой-то момент.