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

Android开发求助:动态列数据库表的AddScoreActivity实现咨询

嗨,看起来你已经搭好了应用的核心框架,接下来要实现分数录入功能对吧?我来一步步给你梳理实现思路和关键代码,帮你搞定AddScoreActivity:

核心思路梳理

因为table2的列数和table1的人名数量完全对应,所以实现逻辑可以拆成这几步:

  1. 从table1拉取所有人员名单
  2. 根据名单动态生成对应的分数录入控件
  3. 校验用户输入的分数合法性
  4. 将分数批量保存/更新到table2

第一步:完善DBHelper的工具方法

首先要给你的DBHelper类补充几个关键方法,用来获取人员名单、同步table2的列结构:

1. 获取所有人员名单

public List<String> getAllPersons() {
    List<String> persons = new ArrayList<>();
    SQLiteDatabase db = this.getReadableDatabase();
    Cursor cursor = db.rawQuery("SELECT name FROM table1", null);
    
    if (cursor.moveToFirst()) {
        do {
            persons.add(cursor.getString(0));
        } while (cursor.moveToNext());
    }
    
    cursor.close();
    db.close();
    return persons;
}

2. 同步table2的列(新增人员时调用)

因为table2的列要和table1的人名一一对应,所以每次在AddPersonActivity添加人员后,需要给table2新增对应列:

public void syncTable2Column(String newPersonName) {
    SQLiteDatabase db = this.getWritableDatabase();
    try {
        // 先检查table2是否存在
        Cursor tableCursor = db.rawQuery(
            "SELECT name FROM sqlite_master WHERE type='table' AND name='table2'", 
            null
        );
        boolean tableExists = tableCursor.moveToFirst();
        tableCursor.close();

        if (!tableExists) {
            // 首次添加人员时创建table2并初始化第一列
            db.execSQL("CREATE TABLE table2 (" + newPersonName + " INTEGER DEFAULT 0)");
        } else {
            // 检查列是否已存在,避免重复添加
            Cursor columnCursor = db.rawQuery("PRAGMA table_info(table2)", null);
            boolean columnExists = false;
            if (columnCursor.moveToFirst()) {
                do {
                    String existingCol = columnCursor.getString(columnCursor.getColumnIndex("name"));
                    if (existingCol.equals(newPersonName)) {
                        columnExists = true;
                        break;
                    }
                } while (columnCursor.moveToNext());
            }
            columnCursor.close();
            
            if (!columnExists) {
                db.execSQL("ALTER TABLE table2 ADD COLUMN " + newPersonName + " INTEGER DEFAULT 0");
            }
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        db.close();
    }
}

记得在AddPersonActivity添加人员成功后调用这个方法:

if (dbHelper.addPerson(newPersonName)) {
    dbHelper.syncTable2Column(newPersonName);
    Toast.makeText(this, "人员添加成功", Toast.LENGTH_SHORT).show();
    finish();
}

第二步:实现AddScoreActivity

1. 布局文件(activity_add_score.xml)

用滚动布局适配多人员场景,动态生成的录入控件放在容器里:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">

        <LinearLayout
            android:id="@+id/ll_score_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:gap="12dp"/>
    </ScrollView>

    <Button
        android:id="@+id/btn_save_scores"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="保存所有分数"/>
</LinearLayout>

2. Activity逻辑代码

public class AddScoreActivity extends AppCompatActivity {
    private DBHelper dbHelper;
    private LinearLayout scoreContainer;
    private List<String> personList;
    private List<EditText> scoreInputList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_score);

        dbHelper = new DBHelper(this);
        scoreContainer = findViewById(R.id.ll_score_container);
        Button saveBtn = findViewById(R.id.btn_save_scores);

        // 获取人员名单
        personList = dbHelper.getAllPersons();
        if (personList.isEmpty()) {
            Toast.makeText(this, "暂无人员,请先添加", Toast.LENGTH_SHORT).show();
            saveBtn.setEnabled(false);
            return;
        }

        // 动态生成录入控件
        generateScoreInputs();

        // 保存按钮点击事件
        saveBtn.setOnClickListener(v -> saveScoresToDB());
    }

    private void generateScoreInputs() {
        for (String person : personList) {
            // 每行布局:人名 + 分数输入框
            LinearLayout rowLayout = new LinearLayout(this);
            rowLayout.setOrientation(LinearLayout.HORIZONTAL);
            rowLayout.setGravity(Gravity.CENTER_VERTICAL);
            rowLayout.setGap(8dp);

            // 人名文本
            TextView personTv = new TextView(this);
            personTv.setText(person);
            personTv.setLayoutParams(new LinearLayout.LayoutParams(
                0,
                LinearLayout.LayoutParams.WRAP_CONTENT,
                1f
            ));

            // 分数输入框(限制整数输入)
            EditText scoreEt = new EditText(this);
            scoreEt.setHint("输入分数");
            scoreEt.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_SIGNED);
            scoreEt.setLayoutParams(new LinearLayout.LayoutParams(
                0,
                LinearLayout.LayoutParams.WRAP_CONTENT,
                1f
            ));
            scoreInputList.add(scoreEt);

            rowLayout.addView(personTv);
            rowLayout.addView(scoreEt);
            scoreContainer.addView(rowLayout);
        }
    }

    private void saveScoresToDB() {
        // 收集并校验分数
        List<Integer> scores = new ArrayList<>();
        boolean isInputValid = true;

        for (EditText et : scoreInputList) {
            String scoreStr = et.getText().toString().trim();
            if (scoreStr.isEmpty()) {
                Toast.makeText(this, "请填写所有分数", Toast.LENGTH_SHORT).show();
                isInputValid = false;
                break;
            }
            try {
                scores.add(Integer.parseInt(scoreStr));
            } catch (NumberFormatException e) {
                Toast.makeText(this, "请输入有效的整数分数", Toast.LENGTH_SHORT).show();
                isInputValid = false;
                break;
            }
        }

        if (!isInputValid) return;

        // 批量保存到table2(用事务保证数据一致性)
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        db.beginTransaction();
        try {
            ContentValues values = new ContentValues();
            for (int i = 0; i < personList.size(); i++) {
                values.put(personList.get(i), scores.get(i));
            }

            // 判断table2是否已有数据,有则更新,无则插入
            Cursor cursor = db.rawQuery("SELECT * FROM table2 LIMIT 1", null);
            if (cursor.moveToFirst()) {
                db.update("table2", values, null, null);
            } else {
                db.insert("table2", null, values);
            }
            cursor.close();

            db.setTransactionSuccessful();
            Toast.makeText(this, "分数保存成功", Toast.LENGTH_SHORT).show();
            finish();
        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(this, "保存失败,请重试", Toast.LENGTH_SHORT).show();
        } finally {
            db.endTransaction();
            db.close();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (dbHelper != null) {
            dbHelper.close();
        }
    }
}

关键注意事项
  1. 输入校验:通过InputType限制输入为整数,同时在保存时捕获格式异常,避免崩溃
  2. 事务处理:批量操作数据库时用事务,防止部分数据保存失败导致的不一致
  3. 动态列同步:一定要保证table2的列和table1的人名完全同步,否则会出现保存失败的情况
  4. 空状态处理:当table1没有人员时,禁用保存按钮并提示用户先添加人员

内容的提问来源于stack exchange,提问作者Mohammad Reza Norasideh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:09:09