Android RecyclerView删除Workout后关联Exercise误删问题求助
健身记录App删除Workout时误删其他Workout关联Exercise的问题修复
问题描述
开发健身记录App,核心功能如下:
- 点击+按钮弹出带输入框的对话框,输入Workout名称后可将其添加至RecyclerView
- 点击Workout项进入详情页,在详情页点击+可添加该Workout关联的Exercise
- 使用SharedPreferences存储数据,通过HashMap管理Workout与对应Exercise列表的关联
当前遇到问题:删除第一个Workout时,第二个Workout的关联Exercise会被误删。
问题根源分析
- 重复删除与保存操作:
FitNotes的SwipeToDeleteCallback.onSwiped()方法中,先手动删除列表中的Workout项,又调用deleteWorkout()再次遍历列表删除同名项,同时重复执行数据保存操作,易导致数据状态不一致。 - 以Workout名称作为HashMap Key存在冲突风险:若创建同名Workout,它们会共用同一个HashMap Key,删除其中一个时,对应Key下的Exercise列表会被整体移除,导致其他同名Workout的Exercise丢失。
- 冗余代码干扰:
WorkoutActivity中重复加载exercisesMap,虽不直接引发问题,但会增加不必要的IO操作。
修复方案
1. 清理重复的删除与保存逻辑
修改FitNotes的SwipeToDeleteCallback.onSwiped()方法,移除重复操作,统一调用deleteWorkout()处理删除逻辑:
@Override public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { int position = viewHolder.getAdapterPosition(); WorkoutItem deletedWorkout = workoutList.get(position); Log.d("SwipedWorkout", "Deleting workout: " + deletedWorkout.getName()); deleteWorkout(deletedWorkout.getName()); recyclerViewAdapter.notifyItemRemoved(position); recyclerViewAdapter.notifyItemRangeChanged(position, workoutList.size()); updateInstructionsVisibility(); }
调整deleteWorkout()方法,确保仅执行一次列表删除与数据保存:
public void deleteWorkout(String workoutName) { Iterator<WorkoutItem> iterator = workoutList.iterator(); while (iterator.hasNext()) { WorkoutItem workoutItem = iterator.next(); if (workoutItem.getName().equals(workoutName)) { iterator.remove(); if (exercisesMap.containsKey(workoutName)) { exercisesMap.remove(workoutName); Log.d("deleteWorkout", "Exercises removed for workout: " + workoutName); } else { Log.e("deleteWorkout", "No exercises found for workout: " + workoutName); } saveData(); saveExercisesMap(); updateInstructionsVisibility(); break; } } }
2. 为Workout添加唯一ID,避免Key冲突
修改WorkoutItem类,添加UUID作为唯一ID,用ID替代名称作为exercisesMap的Key:
public class WorkoutItem { private String id; private String name; public WorkoutItem(String name) { this.id = UUID.randomUUID().toString(); this.name = name; } public String getId() { return id; } public String getName() { return name; } }
同步修改FitNotes中涉及exercisesMap的操作:
- 添加Workout时:
WorkoutItem newWorkout = new WorkoutItem(workoutName); workoutList.add(newWorkout); exercisesMap.put(newWorkout.getId(), new ArrayList<>());
- 删除Workout时:
exercisesMap.remove(workoutItem.getId());
- 跳转至
WorkoutActivity时:
String workoutId = workoutList.get(position).getId(); Intent intent = new Intent(FitNotes.this, Workout.class); intent.putExtra("WORKOUT_ID", workoutId); intent.putExtra("WORKOUT_NAME", workoutList.get(position).getName()); startActivity(intent);
修改WorkoutActivity,通过ID获取对应Exercise列表:
String selectedWorkoutId = getIntent().getStringExtra("WORKOUT_ID"); String selectedWorkoutName = getIntent().getStringExtra("WORKOUT_NAME"); textViewWorkoutName.setText(selectedWorkoutName); // ... exerciseList = exercisesMap.get(selectedWorkoutId); if (exerciseList == null) { exerciseList = new ArrayList<>(); exercisesMap.put(selectedWorkoutId, exerciseList); }
3. 清理WorkoutActivity中的冗余代码
移除重复的loadExercisesMap()调用:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getSupportActionBar().hide(); setContentView(R.layout.activity_workout); btnAddExercise = findViewById(R.id.btnAddExercise); recyclerView = findViewById(R.id.recycler_workoutExercise); textViewWorkoutName = findViewById(R.id.textView_workoutName); textViewInstructions = findViewById(R.id.textViewInstructions); String selectedWorkoutId = getIntent().getStringExtra("WORKOUT_ID"); String selectedWorkoutName = getIntent().getStringExtra("WORKOUT_NAME"); textViewWorkoutName.setText(selectedWorkoutName); exerciseList = new ArrayList<>(); exercisesMap = loadExercisesMap(); if (exercisesMap == null) { exercisesMap = new HashMap<>(); } exerciseList = exercisesMap.get(selectedWorkoutId); if (exerciseList == null) { exerciseList = new ArrayList<>(); exercisesMap.put(selectedWorkoutId, exerciseList); } recyclerViewAdapter = new WorkoutExerciseAdapter(this, exerciseList); recyclerView.setAdapter(recyclerViewAdapter); recyclerView.setLayoutManager(new LinearLayoutManager(this)); ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new Workout.SwipeToDeleteCallback()); itemTouchHelper.attachToRecyclerView(recyclerView); updateInstructionsVisibility(exerciseList); btnAddExercise.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { showAddExerciseDialog(); } }); }
总结
通过清理重复操作、为Workout添加唯一ID作为HashMap的Key,可彻底解决删除Workout时误删其他Workout关联Exercise的问题,同时提升数据存储的稳定性。
内容的提问来源于stack exchange,提问作者VGoychev
相关产品推荐
相关产品推荐

