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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 16:32:02