You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android RecyclerView删除Workout后关联Exercise误删问题求助

健身记录App删除Workout时误删其他Workout关联Exercise的问题修复

问题描述

开发健身记录App,核心功能如下:

  • 点击+按钮弹出带输入框的对话框,输入Workout名称后可将其添加至RecyclerView
  • 点击Workout项进入详情页,在详情页点击+可添加该Workout关联的Exercise
  • 使用SharedPreferences存储数据,通过HashMap管理Workout与对应Exercise列表的关联

当前遇到问题:删除第一个Workout时,第二个Workout的关联Exercise会被误删。

问题根源分析

  1. 重复删除与保存操作:FitNotes的SwipeToDeleteCallback.onSwiped()方法中,先手动删除列表中的Workout项,又调用deleteWorkout()再次遍历列表删除同名项,同时重复执行数据保存操作,易导致数据状态不一致。
  2. 以Workout名称作为HashMap Key存在冲突风险:若创建同名Workout,它们会共用同一个HashMap Key,删除其中一个时,对应Key下的Exercise列表会被整体移除,导致其他同名Workout的Exercise丢失。
  3. 冗余代码干扰: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 13:39:54