我现在正在开发锻炼日志应用程序。
两个项目 ( routine and routine detail) 用 表示one recycler view and adapter。
如果我单击添加例程按钮,则会添加一个例程项,并且例程基本上有一个例程详细项。
日常项目有按钮add or delete routine detail items。
我曾经DiffUtil更新项目。
在areItemsTheSame()中,我曾经hashCode比较oldList和newList。
但是,在添加或删除项目时会出现一个原因不明的问题。(不是错误)。
如果我在添加例程项目和详细项目后单击删除按钮,它首先运行良好。
除非按下上一个例程项的删除按钮,否则下一个例程项的例程详细按钮不能添加或删除。
如果上一个例程项目的删除按钮被按下,然后下一个项目的按钮被按下,则执行添加或删除。
为什么是这样?
当您使用hashCode comparison.
但是,equals()这不会发生并且工作正常。
相反,每次添加或删除项目时,整个项目都会闪烁更新。
我必须如何定义 DiffUtil 类?
代码
例程模型.java
public class RoutineModel {
private ArrayList<RoutineDetailModel> routineDetailList;
private String routine;
public RoutineModel(String routine) {
this.routine = routine;
}
public void addDetail(RoutineDetailModel item) {
if(routineDetailList == null) {
routineDetailList = new ArrayList<>();
}
this.routineDetailList.add(item);
}
public ArrayList<RoutineDetailModel> getDetailItemList() {
return routineDetailList;
}
public int getDetailItemSize() {
return routineDetailList.size();
}
public String getRoutine() {
return routine;
}
public void removeDetails(int index) throws Exception {
this.routineDetailList.remove(index);
}
@Override
public int hashCode() {
return Objects.hash(routineDetailList, routine);
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
RoutineModel that = (RoutineModel) obj;
return Objects.equals(routine, that.routine) && Objects.equals(routineDetailList, that.routineDetailList);
}
}
例程适配器.java
public class RoutineAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
final static int TYPE_ROUTINE = 1;
final static int TYPE_ROUTINE_DETAIL = 2;
private Context context;
private List<Object> mItems = new ArrayList<>();
OnRoutineItemClickListener listener;
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();
if (viewType == TYPE_ROUTINE) {
View itemView = LayoutInflater.from(context).inflate(R.layout.routine_item, parent, false);
return new RoutineViewHolder(itemView);
}
View itemView = LayoutInflater.from(context).inflate(R.layout.routine_detail_item, parent, false);
return new RoutineDetailViewHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
Object object = mItems.get(position);
if(object instanceof RoutineModel) {
setRoutineData((RoutineViewHolder) holder, (RoutineModel) object, position);
}
else if(object instanceof RoutineDetailModel) {
}
}
private void setRoutineData(RoutineViewHolder holder, RoutineModel routineItem, int position){
holder.routine.setText(routineItem.getRoutine());
holder.addSet.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(listener != null) listener.OnAddBtnClick(position);
}
});
holder.deleteSet.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(listener != null) listener.OnDeleteBtnClick(position);
}
});
}
public Object getRoutineItem(int position) {
if(mItems == null || position < 0 || position >= mItems.size())
return null;
return mItems.get(position);
}
@Override
public int getItemCount() {
if(mItems == null)
return -1;
return mItems.size();
}
@Override
public int getItemViewType(int position) {
Object obj = mItems.get(position);
if(obj instanceof RoutineModel) {
return TYPE_ROUTINE;
}
return TYPE_ROUTINE_DETAIL;
}
// detail add,delete click interface
public interface OnRoutineItemClickListener {
public void OnAddBtnClick(int curRoutinePos);
public void OnDeleteBtnClick(int curRoutinePos);
}
public void setOnRoutineClickListener(OnRoutineItemClickListener listener) {
this.listener = listener;
}
public class RoutineViewHolder extends RecyclerView.ViewHolder {
public TextView routine;
public Button addSet;
public Button deleteSet;
public RoutineViewHolder(@NonNull View itemView) {
super(itemView);
routine = itemView.findViewById(R.id.routine);
addSet = itemView.findViewById(R.id.add_set);
deleteSet = itemView.findViewById(R.id.delete_set);
}
}
public class RoutineDetailViewHolder extends RecyclerView.ViewHolder {
public TextView set;
public TextView weight;
public RoutineDetailViewHolder(@NonNull View itemView) {
super(itemView);
set = itemView.findViewById(R.id.set);
weight = itemView.findViewById(R.id.weight);
}
}
}
RoutineDiffUtil.java
public class RoutineDiffUtil extends DiffUtil.Callback {
private List<Object> oldRoutineList;
private List<Object> newRoutineList;
public RoutineDiffUtil(List<Object> oldRoutineList) {
this.oldRoutineList = oldRoutineList;
newRoutineList = new ArrayList<>();
}
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) {
// boolean result = oldRoutineList.equals(newRoutineList); // work well
boolean result = oldRoutineList.get(oldItemPosition).hashCode() == newRoutineList.get(newItemPosition).hashCode();
return result;
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return oldRoutineList.get(oldItemPosition).equals(newRoutineList.get(newItemPosition));
}
}
MainActivity.java
public class WriteRoutineActivity extends AppCompatActivity {
Button add_routine_btn;
TextView title;
RecyclerView routine_rv;
LinearLayoutManager routineLayoutManger;
RoutineAdapter routineAdapter;
List<RoutineModel> items;
List<String> titleData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_write_routine);
initViews();
setPageTitle(getIntent());
setRoutineRecyclerview();
items = new ArrayList<>();
routineAdapter = new RoutineAdapter();
routine_rv.setAdapter(routineAdapter);
add_routine_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
WorkoutListDialogFragment routineDialog = new WorkoutListDialogFragment();
routineDialog.show(getSupportFragmentManager(), "RoutineListDialog");
}
});
routineAdapter.setOnRoutineClickListener(new RoutineAdapter.OnRoutineItemClickListener() {
@Override
public void OnAddBtnClick(int routinePos) {
Object obj = routineAdapter.getRoutineItem(routinePos);
if(obj instanceof RoutineModel) {
RoutineModel item = (RoutineModel) obj;
item.addDetail(new RoutineDetailModel());
routineAdapter.updateRoutineList(getDataToBeDisplayed());
}
}
@Override
public void OnDeleteBtnClick(int routinePos) {
Object item = routineAdapter.getRoutineItem(routinePos);
if(item instanceof RoutineModel) {
RoutineModel routineModel = (RoutineModel) item;
if(routineModel.getDetailItemSize() > 1) {
try {
routineModel.removeDetails(routineModel.getDetailItemSize() - 1);
} catch (Exception e) {
e.printStackTrace();
}
}
else { // if delete item exists only one
items.remove(routineModel);
}
routineAdapter.updateRoutineList(getDataToBeDisplayed());
}
}
});
}
public void addRoutine(String routine) {
RoutineModel routineModel = new RoutineModel(routine);
RoutineDetailModel routineDetailModel = new RoutineDetailModel();
routineModel.addDetail(routineDetailModel);
items.add(routineModel);
routineAdapter.updateRoutineList(getDataToBeDisplayed());
}
private List<Object> getDataToBeDisplayed() {
List<Object> mixedList = new ArrayList<>();
for(RoutineModel rm: items){
mixedList.add(rm);
if(rm.getDetailItemList() != null && rm.getDetailItemSize() > 0){
for(RoutineDetailModel rmdetilas: rm.getDetailItemList()){
mixedList.add(rmdetilas);
}
}
}
return mixedList;
}
}

