I have attached a picture to help you understand my problem.
I'm making an Workout app.
When the button is pressed, the routine is added In the added routine, it can use the button again to add detailed data (set, lbs, reps).
So, I am using a two type RecyclerView
(except footer).
I used DiffUtil
to update the items being added.
I found a strange phenomenon while experimenting for testing. (See photo)
It wasn't an error, so I can't figure out what's wrong with it.
After entering the data, when i added a number of detailed items, the value of the data entered first appeared in the items added later.
And if i scrolled after many items were added, the data moved randomly.
However, what is expected is this phenomenon when you add a lot of items or scroll.
What's wrong?
RoutineAdapter.java
public class RoutineAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
final static int TYPE_ROUTINE = 1;
final static int TYPE_ROUTINE_DETAIL = 2;
final static int TYPE_ROUTINE_FOOTER = 3;
private Context context;
private List<Object> mItems = new ArrayList<>();
OnRoutineItemClickListener routinelistener;
OnRoutineAddClickListener routineAddListener;
public void updateRoutineList(List<Object> newRoutineList) {
final RoutineDiffUtil diffCallback = new RoutineDiffUtil(this.mItems, newRoutineList);
final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback);
this.mItems.clear();
this.mItems.addAll(newRoutineList);
diffResult.dispatchUpdatesTo(this);
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
context = parent.getContext();
View itemView;
if(viewType == TYPE_ROUTINE){
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.routine_item, parent, false);
return new RoutineViewHolder(itemView);
}
else if(viewType == TYPE_ROUTINE_DETAIL){
itemView = LayoutInflater.from(context).inflate(R.layout.routine_detail_item, parent, false);
return new RoutineDetailViewHolder(itemView);
}
else {
itemView = LayoutInflater.from(context).inflate(R.layout.add_routine_item, parent, false);
return new RoutineAddFooterViewHolder(itemView);
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
Object obj;
switch (getItemViewType(position)) {
case TYPE_ROUTINE:
obj = mItems.get(position);
setRoutineData((RoutineViewHolder) holder, (RoutineModel) obj);
break;
case TYPE_ROUTINE_DETAIL:
obj = mItems.get(position);
RoutineDetailModel item = (RoutineDetailModel) obj;
((RoutineDetailViewHolder) holder).setDetailItem(item);
break;
case TYPE_ROUTINE_FOOTER:
break;
}
}
@Override
public int getItemCount() {
if(mItems == null)
return -1;
return mItems.size() + 1; // for footer
}
@Override
public int getItemViewType(int position) {
if(position == mItems.size()) {
return TYPE_ROUTINE_FOOTER;
}
else {
Object obj = mItems.get(position);
if(obj instanceof RoutineModel) {
return TYPE_ROUTINE;
}
else {
// obj instanceof RoutineDetailModel
return TYPE_ROUTINE_DETAIL;
}
}
}
// add routine interface
public interface OnRoutineAddClickListener {
public void onAddRoutineClick();
}
public void setOnAddRoutineClickListener(OnRoutineAddClickListener listener) {
this.routineAddListener = listener;
}
// details add / remove interface
public interface OnRoutineItemClickListener {
public void onAddBtnClicked(int curRoutinePos);
public void onDeleteBtnClicked(int curRoutinePos);
public void onWritingCommentBtnClicked(int curRoutinePos);
}
public void setOnRoutineClickListener(OnRoutineItemClickListener listener) {
this.routinelistener = listener;
}
private class RoutineViewHolder extends RecyclerView.ViewHolder {
public TextView routine;
public Button addSet;
public Button deleteSet;
public Button comment;
public RoutineViewHolder(@NonNull View itemView) {
super(itemView);
initViews();
addSet.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(routinelistener != null && getAdapterPosition() != RecyclerView.NO_POSITION)
routinelistener.onAddBtnClicked(getAdapterPosition());
}
});
deleteSet.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(routinelistener != null && getAdapterPosition() != RecyclerView.NO_POSITION)
routinelistener.onDeleteBtnClicked(getAdapterPosition());
}
});
comment.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(routinelistener != null && getAdapterPosition() != RecyclerView.NO_POSITION)
routinelistener.onWritingCommentBtnClicked(getAdapterPosition());
}
});
}
}
private class RoutineDetailViewHolder extends RecyclerView.ViewHolder {
public TextView set;
public TextView weight;
public RoutineDetailViewHolder(@NonNull View itemView) {
super(itemView);
initViews();
}
private void initViews() {
set = itemView.findViewById(R.id.set);
weight = itemView.findViewById(R.id.weight);
}
private void setDetailItem(RoutineDetailModel item) {
set.setText(item.getSet().toString() + "set");
}
}
}
RoutineDiffUtil.java
public class RoutineDiffUtil extends DiffUtil.Callback {
private List<Object> oldRoutineList;
private List<Object> newRoutineList;
public RoutineDiffUtil(List<Object> oldRoutineList, List<Object> newRoutineList) {
this.oldRoutineList = oldRoutineList;
this.newRoutineList = newRoutineList;
}
@Override
public int getOldListSize() {
return oldRoutineList.size();
}
@Override
public int getNewListSize() {
return newRoutineList.size();
}
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
Object oldObj = oldRoutineList.get(oldItemPosition);
Object newObj = newRoutineList.get(newItemPosition);
if (oldObj instanceof RoutineModel && newObj instanceof RoutineModel) {
return ((RoutineModel) oldObj).id == ((RoutineModel) newObj).id;
}
else if (oldObj instanceof RoutineDetailModel && newObj instanceof RoutineDetailModel) {
return ((RoutineDetailModel) oldObj).id == ((RoutineDetailModel) newObj).id;
}
else if(oldObj instanceof RoutineModel && newObj instanceof RoutineDetailModel) {
return false;
}
else {
return false;
}
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return (oldRoutineList.get(oldItemPosition)).equals(newRoutineList.get(newItemPosition));
}
}
RoutineDetailModel.java
public class RoutineDetailModel {
public int id;
private int set = 1;
private int weight;
public RoutineDetailModel() {
Random random = new Random();
this.id = random.nextInt();
}
public RoutineDetailModel(int set) {
Random random = new Random();
this.id = random.nextInt();
this.set = set+1;
}
public Integer getSet() {
return set;
}
public int getId() {
return id;
}
@Override
public int hashCode() {
return Objects.hash(set, weight);
}
@Override
public boolean equals(@Nullable Object obj) {
if(obj != null && obj instanceof RoutineDetailModel) {
RoutineDetailModel model = (RoutineDetailModel) obj;
if(this.id == model.getId()) {
return true;
}
}
return false;
}
}