如何在SQLite中实现删除单个清单项而非整个清单的方法
相关代码片段
以下为用于向数据库添加清单的Activity代码:
public class AddChecklist extends AppCompatActivity { Button btnAddItem; public LinearLayout linearLayout; ArrayList<String> itemList; ArrayList<String> stateList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_add_checklist); btnAddItem.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { addView(); } }); } public void addView() { View checklistView = getLayoutInflater().inflate(R.layout.checklist_view, null, false); EditText etChecklistItem = checklistView.findViewById(R.id.et_checklist_item); etChecklistItem.requestFocus(); linearLayout.addView(checklistView); ImageView imgDelete = checklistView.findViewById(R.id.img_delete); imgDelete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { removeView(checklistView); } }); } public void removeView(View view) { linearLayout.removeView(view); } @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { DbHelper dbHelper = new DbHelper(getApplicationContext()); switch (item.getItemId()) { case R.id.btn_save: ChecklistHelper checklistHelper = new ChecklistHelper(); for (int i = 0; i < linearLayout.getChildCount(); i++) { View v = linearLayout.getChildAt(i); EditText etChecklistItem = v.findViewById(R.id.et_checklist_item); CheckBox checkBox = v.findViewById(R.id.check_box); if (checkBox.isChecked()) { checklistHelper.setStatus("1"); } else checklistHelper.setStatus("0"); itemList.add(etChecklistItem.getText().toString()); stateList.add(checklistHelper.getStatus()); } StringBuilder stringBuilder = new StringBuilder(); for (String items : itemList) { stringBuilder.append(items); stringBuilder.append("\n"); } StringBuilder stringBuilder1 = new StringBuilder(); for (String state : stateList) { stringBuilder1.append(state); stringBuilder1.append("\n"); } String items = stringBuilder.toString(); String state = stringBuilder1.toString(); dbHelper.insertChecklist(state, items, DateTime.date(), DateTime.time(), System.currentTimeMillis()); finish(); break; } return true; } }
以下为SQLiteHelper类中的清单插入方法:
public boolean insertChecklist(String status, String content, String date, String time, long now){ SQLiteDatabase sqLiteDatabase = this.getWritableDatabase(); ContentValues c = new ContentValues(); c.put(CHECKLIST_STATUS, status); c.put(CHECKLIST_CONTENT, content); c.put(CHECKLIST_DATE, date); c.put(CHECKLIST_TIME, time); c.put(CHECKLIST_NOW, now); long id = sqLiteDatabase.insert(CHECKLIST_TABLE, null, c); Log.d("check", "checklist inserted -> ID = " + id); return true; }
以下为现有删除整个清单的方法,暂不支持删除单个条目:
public void deleteChecklist(long id){ SQLiteDatabase db = this.getWritableDatabase(); db.delete(CHECKLIST_TABLE, CHECKLIST_ID + " =? ", new String[] {String.valueOf(id)}); }
需求:实现一个与上述方法结构类似的数据库操作方法,仅删除清单内选中的单个条目。
实现方案
你当前的存储逻辑是把同个清单下的所有条目内容、勾选状态分别用换行符拼接成两个长字符串,存在单条数据库记录中,不需要删除整行表数据,只需要移除对应位置的条目和状态后更新原记录即可。
1. 在DbHelper类中添加单条条目删除方法
方法结构和你已有的增删方法保持一致:
/** * 删除清单内的单个条目 * @param checklistId 目标清单的数据库ID * @param deleteItemPosition 要删除的条目在清单内的位置索引,从0开始计数 */ public void deleteSingleChecklistItem(long checklistId, int deleteItemPosition) { SQLiteDatabase db = this.getWritableDatabase(); // 查询拿到当前清单已存储的内容和状态字符串 Cursor cursor = db.query(CHECKLIST_TABLE, new String[]{CHECKLIST_CONTENT, CHECKLIST_STATUS}, CHECKLIST_ID + " = ?", new String[]{String.valueOf(checklistId)}, null, null, null); if (cursor.moveToFirst()) { String originContent = cursor.getString(cursor.getColumnIndexOrThrow(CHECKLIST_CONTENT)); String originStatus = cursor.getString(cursor.getColumnIndexOrThrow(CHECKLIST_STATUS)); cursor.close(); // 按换行拆分出条目列表、状态列表,过滤末尾换行产生的空值 ArrayList<String> itemList = new ArrayList<>(); for (String item : originContent.split("\n")) { if (!item.trim().isEmpty()) itemList.add(item); } ArrayList<String> stateList = new ArrayList<>(); for (String state : originStatus.split("\n")) { if (!state.trim().isEmpty()) stateList.add(state); } // 校验位置合法性后,移除对应索引的条目和状态 if (deleteItemPosition >= 0 && deleteItemPosition < itemList.size() && deleteItemPosition < stateList.size()) { itemList.remove(deleteItemPosition); stateList.remove(deleteItemPosition); } // 重新拼接为符合存储格式的字符串 StringBuilder contentSb = new StringBuilder(); for (String item : itemList) { contentSb.append(item).append("\n"); } StringBuilder statusSb = new StringBuilder(); for (String state : stateList) { statusSb.append(state).append("\n"); } // 更新原数据库记录 ContentValues cv = new ContentValues(); cv.put(CHECKLIST_CONTENT, contentSb.toString()); cv.put(CHECKLIST_STATUS, statusSb.toString()); db.update(CHECKLIST_TABLE, cv, CHECKLIST_ID + " = ?", new String[]{String.valueOf(checklistId)}); } }
2. 页面层绑定删除点击事件
在渲染每个清单条目的时候,给删除按钮设置Tag存储当前条目所属的清单ID、自身位置索引,点击时直接调用上述方法即可:
// checklistId为当前打开的清单的数据库ID,currentItemPosition为当前条目渲染时的索引 imgDelete.setTag(R.id.tag_checklist_id, checklistId); imgDelete.setTag(R.id.tag_item_position, currentItemPosition); imgDelete.setOnClickListener(v -> { long cId = (long) v.getTag(R.id.tag_checklist_id); int pos = (int) v.getTag(R.id.tag_item_position); // 调用删除方法 dbHelper.deleteSingleChecklistItem(cId, pos); // 重新加载数据刷新页面 loadChecklistData(); });
注意事项
- 传入的
deleteItemPosition需要和条目在页面上展示的顺序、拆分后的列表索引完全对应,避免删错条目 - 拆分字符串时过滤空值是为了处理拼接时末尾多生成的空行,防止索引错位
- 如果后续需要频繁对单条清单条目做增删、修改勾选状态操作,建议拆分两张关联表存储:主表存清单创建时间、名称等基础信息,子表存单个清单项的内容、勾选状态、关联的主表ID,长期维护成本远低于字符串拼接的存储方案
内容的提问来源于stack exchange,提问作者nano tech
相关产品推荐
相关产品推荐

