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

Android健身房训练APP开发:SimpleCursorAdapter与一对多数据存储技术问询

嘿,我来帮你梳理下这个健身房训练追踪App的功能实现思路,结合你已经有的数据库助手类和训练查看Activity,咱们一步步拆解来做:

第一步:确认/调整数据库表结构

要实现训练项目和练习的一对多关联,咱们需要两张关联的表:

  • 训练表(比如命名为workouts):你已经有_id主键,再加上存储训练名称的workout_name字段就够了
  • 练习表(比如命名为exercises):除了_id主键和存储练习名称的exercise_name,还得加一个workout_id外键,用来关联对应训练项目的_id

在你的数据库助手类(DBHelper)里,更新onCreate方法的建表语句:

@Override
public void onCreate(SQLiteDatabase db) {
    // 开启外键约束,保证关联数据的完整性
    db.execSQL("PRAGMA foreign_keys = ON;");
    
    // 创建训练表
    db.execSQL("CREATE TABLE workouts (_id INTEGER PRIMARY KEY AUTOINCREMENT, workout_name TEXT NOT NULL);");
    // 创建练习表,通过workout_id关联训练表
    db.execSQL("CREATE TABLE exercises (_id INTEGER PRIMARY KEY AUTOINCREMENT, exercise_name TEXT NOT NULL, workout_id INTEGER NOT NULL, FOREIGN KEY(workout_id) REFERENCES workouts(_id));");
}
第二步:添加练习Activity的核心实现

首先,用户在命名训练项目后,你需要先把训练名称插入训练表,拿到对应的_id,再通过Intent把这个ID传递到添加练习的Activity里——这是关联训练和练习的关键。

2.1 接收训练ID并初始化ListView

在添加练习的Activity的onCreate方法里,先获取传递过来的训练ID,然后用SimpleCursorAdapter初始化ListView:

// 获取从训练命名界面传递来的训练ID
long workoutId = getIntent().getLongExtra("EXTRA_WORKOUT_ID", -1);
if (workoutId == -1) {
    // 如果没拿到有效ID,直接返回上一页
    finish();
    return;
}

// 初始化数据库连接和Cursor
DBHelper dbHelper = new DBHelper(this);
SQLiteDatabase db = dbHelper.getReadableDatabase();

// 查询当前训练下的所有练习,用来填充ListView
Cursor exerciseCursor = db.query(
    "exercises",
    new String[]{"_id", "exercise_name"}, // 只查需要的列
    "workout_id = ?", // 过滤条件:只属于当前训练的练习
    new String[]{String.valueOf(workoutId)},
    null, null, null
);

// 设置SimpleCursorAdapter
SimpleCursorAdapter adapter = new SimpleCursorAdapter(
    this,
    android.R.layout.simple_list_item_1, // 用系统默认的列表项布局,也可以自定义
    exerciseCursor,
    new String[]{"exercise_name"}, // Cursor里对应的列名
    new int[]{android.R.id.text1}, // 布局里用来显示练习名称的TextView ID
    0
);

ListView exerciseListView = findViewById(R.id.list_exercises);
exerciseListView.setAdapter(adapter);

2.2 实现添加练习的功能

假设你的布局里有输入练习名称的EditText(id: et_exercise_name)和添加按钮(id: btn_add_exercise),给按钮加点击事件:

EditText etExerciseName = findViewById(R.id.et_exercise_name);
Button btnAddExercise = findViewById(R.id.btn_add_exercise);

btnAddExercise.setOnClickListener(v -> {
    String exerciseName = etExerciseName.getText().toString().trim();
    if (!exerciseName.isEmpty()) {
        // 准备要插入练习的数据
        ContentValues values = new ContentValues();
        values.put("exercise_name", exerciseName);
        values.put("workout_id", workoutId); // 关联当前训练ID
        
        // 插入到数据库
        db.insert("exercises", null, values);
        
        // 刷新Cursor和Adapter,让新添加的练习立刻显示在ListView上
        Cursor newCursor = db.query(
            "exercises",
            new String[]{"_id", "exercise_name"},
            "workout_id = ?",
            new String[]{String.valueOf(workoutId)},
            null, null, null
        );
        adapter.swapCursor(newCursor);
        
        // 清空输入框,方便继续添加
        etExerciseName.setText("");
    }
});

2.3 完成按钮的逻辑

当用户点击完成按钮时,只需关闭当前Activity,回到训练查看界面即可——如果需要通知训练查看界面刷新数据,可以设置返回结果:

Button btnFinish = findViewById(R.id.btn_finish);
btnFinish.setOnClickListener(v -> {
    // 设置返回结果,让训练查看界面知道可以刷新数据
    setResult(RESULT_OK);
    finish();
});
第三步:训练查看Activity的关联展示

在训练查看界面,当用户选中某个训练项目时,你需要查询该训练下的所有练习,同样用SimpleCursorAdapter展示:

// 假设当前选中的训练ID是selectedWorkoutId
Cursor exerciseCursor = db.query(
    "exercises",
    new String[]{"_id", "exercise_name"},
    "workout_id = ?",
    new String[]{String.valueOf(selectedWorkoutId)},
    null, null, null
);

SimpleCursorAdapter exerciseAdapter = new SimpleCursorAdapter(
    this,
    android.R.layout.simple_list_item_1,
    exerciseCursor,
    new String[]{"exercise_name"},
    new int[]{android.R.id.text1},
    0
);

ListView workoutExerciseList = findViewById(R.id.list_workout_exercises);
workoutExerciseList.setAdapter(exerciseAdapter);
几个关键注意事项
  • 记得管理Cursor和数据库连接:在Activity的onDestroy方法里关闭Cursor和数据库,避免内存泄漏;更推荐用CursorLoader来管理Cursor,它会自动处理生命周期,数据变化时自动刷新。
  • 输入验证:一定要检查用户输入的训练名称、练习名称是否为空,避免插入无效数据。
  • 级联操作(可选):如果需要删除训练时自动删除对应的所有练习,可以在建练习表时添加ON DELETE CASCADE,比如把练习表的建表语句改成:
    db.execSQL("CREATE TABLE exercises (_id INTEGER PRIMARY KEY AUTOINCREMENT, exercise_name TEXT NOT NULL, workout_id INTEGER NOT NULL, FOREIGN KEY(workout_id) REFERENCES workouts(_id) ON DELETE CASCADE);");
    

内容的提问来源于stack exchange,提问作者user303749

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:18:38