Room数据库中刚删除的项重启应用后复现的问题求助
问题描述
我实现了一个展示餐食条目的RecyclerView,用户可通过AlertDialog添加餐食。当前存在一个异常情况:启动应用后添加餐食,立即删除并退出应用,再次启动时,该餐食会从Room数据库重新加载(相当于未真正删除);但第二次删除该餐食后,就不会再出现此问题。
相关代码
AppDatabase.class
@Database(entities = {FoodItem.class, FoodMenuItem.class}, version = 1) public abstract class AppDatabase extends RoomDatabase { public abstract FoodItemDao foodItemDao(); public abstract FoodMenuItemDao foodMenuItemDao(); private static AppDatabase INSTANCE; public static AppDatabase getInstance(Context context) { if(INSTANCE == null){ INSTANCE = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "DB_NAME") .allowMainThreadQueries() .build(); } return INSTANCE; } }
FoodItem.class
@Entity public class FoodItem { @PrimaryKey(autoGenerate = true) public int id; public String mealName; public double kcal; public double fats; public double proteins; public double carbs; public String date; public int quantity; public FoodItem(String mealName, double kcal, double fats, double carbs, double proteins, String date) { this.mealName = mealName; this.kcal = kcal; this.fats = fats; this.carbs = carbs; this.proteins = proteins; this.date = date; this.quantity = 100; } // Getter和Setter方法 public int getId() { return id; } public String getMealName() { return mealName; } public double getKcal() { return kcal; } public double getFats() { return fats; } public double getProteins() { return proteins; } public double getCarbs() { return carbs; } public String getDate() { return date; } public int getQuantity() { return quantity; } public void setId(int id) { this.id = id; } public void setMealName(String mealName) { this.mealName = mealName; } public void setKcal(double kcal) { this.kcal = kcal; } public void setFats(double fats) { this.fats = fats; } public void setProteins(double proteins) { this.proteins = proteins; } public void setCarbs(double carbs) { this.carbs = carbs; } public void setDate(String date) { this.date = date; } public void setQuantity(int quantity) { this.quantity = quantity; } }
MealAdapter.class 核心方法
public void addMeal(FoodItem meal) { meals.add(meal); notifyItemInserted(meals.size() - 1); } public List<FoodItem> getMeals() { return meals; } public MealAdapter(List<FoodItem> meals) { this.meals = meals; } public FoodItem getMealAt(int position) { return meals.get(position); } public void removeMeal(FoodItem foodItem) { int position = meals.indexOf(foodItem); if (position != -1) { meals.remove(position); notifyItemRemoved(position); } }
FoodItemDao
@Dao public interface FoodItemDao { @Insert void insert(FoodItem foodItem); @Query("SELECT * FROM FoodItem") List<FoodItem> getAllMeals(); @Query("SELECT * FROM FoodItem") FoodItem getMeal(); @Delete void delete(FoodItem foodItem); @Query("SELECT * FROM FoodItem WHERE date = :date") List<FoodItem> getMealsByDate(String date); @Query("DELETE FROM FoodItem WHERE date = :date") void deleteMealsByDate(String date); }
Activity 核心代码
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_macros_calculator); db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "DB_NAME").allowMainThreadQueries().build(); foodMenuItemDao = db.foodMenuItemDao(); foodItemDao = db.foodItemDao(); List<FoodItem> savedMeals = loadTodaysMealsFromDatabase(); for (FoodItem meal : savedMeals) { mealAdapter.addMeal(meal); } updateTotalValues(); } private List<FoodItem> loadTodaysMealsFromDatabase() { String currentDate = dateFormat.format(calendar.getTime()); List<FoodItem> meals = foodItemDao.getMealsByDate(currentDate); Log.d("Database", "Loaded meals: " + meals.size()); return meals; } private class SwipeToDeleteCallback extends ItemTouchHelper.SimpleCallback { SwipeToDeleteCallback() { super(0, ItemTouchHelper.LEFT); } @Override public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) { return false; } @Override public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { int position = viewHolder.getAdapterPosition(); FoodItem deletedMeal = mealAdapter.getMeals().get(position); deleteItem(deletedMeal); updateTotalValues(); } } private void deleteItem(FoodItem foodItem) { AppDatabase database = AppDatabase.getInstance(this.getApplicationContext()); database.foodItemDao().delete(foodItem); Log.d("Database", "Deleted meal: " + foodItem.getMealName()); mealAdapter.removeMeal(foodItem); mealAdapter.notifyDataSetChanged(); updateTotalValues(); } // 添加餐食的AlertDialog确认按钮逻辑 builder.setPositiveButton("Add", (dialog, which) -> { int selectedQuantity = getSelectedQuantity(radioGroupQuantities); FoodMenuItem selectedMeal = menuAdapter.getSelectedMeal(); if (selectedMeal != null && selectedQuantity > 0) { String currentDate = dateFormat.format(calendar.getTime()); FoodItem mealToAdd = calculateMealForQuantity(selectedMeal, selectedQuantity); mealToAdd.setDate(currentDate); foodItemDao.insert(mealToAdd); mealAdapter.addMeal(mealToAdd); updateTotalValues(); } }); private void updateTotalValues() { List<FoodItem> meals = mealAdapter.getMeals(); int totalKcal = 0; double totalFats = 0; double totalCarbs = 0; double totalProteins = 0; for (FoodItem meal : meals) { totalKcal += meal.getKcal(); totalFats += meal.getFats(); totalCarbs += meal.getCarbs(); totalProteins += meal.getProteins(); } txtViewTotal.setText("Total - " + totalKcal + "kcal " + totalFats + "g fats " + totalCarbs + "g carbs " + totalProteins +"g proteins"); }
问题原因
问题的核心在于插入餐食后,Room没有将自动生成的主键ID赋值给你创建的FoodItem对象:
- 你使用的
@Insert void insert(FoodItem foodItem)方法不会返回插入后的主键,导致添加到Adapter里的FoodItem对象的id字段还是默认值0。 - 调用
delete(foodItem)时,Room会根据对象的主键匹配数据库记录,但此时id为0,数据库中无对应记录,所以删除操作实际未生效。 - 重启应用后,从数据库查询出的FoodItem对象带有正确的主键ID,此时执行删除操作,Room能找到对应记录并成功删除,因此第二次删除正常。
解决方案
1. 修改Dao的插入方法,返回主键ID
将FoodItemDao中的@Insert方法修改为返回long类型的主键值:
@Dao public interface FoodItemDao { // 替换原来的void insert方法 @Insert long insert(FoodItem foodItem); // 其他方法保持不变 ... }
2. 插入后给FoodItem赋值主键ID
在添加餐食的逻辑中,获取插入返回的ID并设置到mealToAdd对象上:
builder.setPositiveButton("Add", (dialog, which) -> { int selectedQuantity = getSelectedQuantity(radioGroupQuantities); FoodMenuItem selectedMeal = menuAdapter.getSelectedMeal(); if (selectedMeal != null && selectedQuantity > 0) { String currentDate = dateFormat.format(calendar.getTime()); FoodItem mealToAdd = calculateMealForQuantity(selectedMeal, selectedQuantity); mealToAdd.setDate(currentDate); // 获取插入后的主键ID并赋值 long insertedId = foodItemDao.insert(mealToAdd); mealToAdd.setId((int) insertedId); mealAdapter.addMeal(mealToAdd); updateTotalValues(); } });
3. 优化deleteItem方法(可选)
mealAdapter.removeMeal(foodItem)已经调用了notifyItemRemoved(position),无需重复调用notifyDataSetChanged(),可删除该行:
private void deleteItem(FoodItem foodItem) { AppDatabase database = AppDatabase.getInstance(this.getApplicationContext()); database.foodItemDao().delete(foodItem); Log.d("Database", "Deleted meal: " + foodItem.getMealName()); mealAdapter.removeMeal(foodItem); // 移除重复的通知 // mealAdapter.notifyDataSetChanged(); updateTotalValues(); }
内容的提问来源于stack exchange,提问作者VGoychev
相关产品推荐
相关产品推荐

