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

Android(Java)饮食追踪App如何永久保存MealModel列表数据

实现MealModel列表永久存储的方案

前提准备:让MealModel支持序列化

无论选择哪种存储方案,都需要让MealModel类支持对象序列化,才能将对象转换为可存储的格式。

方式1:实现Serializable接口(简单易用)

修改MealModel类,实现Serializable接口:

import java.io.Serializable;

/**
 * This class holds the data to represent one meal item
 */
public class MealModel implements Serializable {
    String mealtype;
    String healthyness;
    String date;
    String pathtoimage; // path in phone gallery
    boolean favorised;

    public MealModel(String mealtype, String healthyness, String date, boolean favorised, String pathtoimage) {
        this.mealtype = mealtype;
        this.healthyness = healthyness;
        this.date = date;
        this.favorised = favorised;
        this.pathtoimage = pathtoimage;
    }

    public String getMealtype() { return mealtype; }
    public String getHealthyness() { return healthyness; }
    public String getPathtoimage() { return pathtoimage; }
    public boolean getFavorised() { return favorised; }
    public String getDate() { return date; }
}

方式2:实现Parcelable接口(Android推荐,效率更高)

如果需要跨组件传递对象,或者追求更高序列化效率,推荐实现Parcelable接口:

import android.os.Parcel;
import android.os.Parcelable;

public class MealModel implements Parcelable {
    String mealtype;
    String healthyness;
    String date;
    String pathtoimage;
    boolean favorised;

    public MealModel(String mealtype, String healthyness, String date, boolean favorised, String pathtoimage) {
        this.mealtype = mealtype;
        this.healthyness = healthyness;
        this.date = date;
        this.favorised = favorised;
        this.pathtoimage = pathtoimage;
    }

    protected MealModel(Parcel in) {
        mealtype = in.readString();
        healthyness = in.readString();
        date = in.readString();
        pathtoimage = in.readString();
        favorised = in.readByte() != 0;
    }

    public static final Creator<MealModel> CREATOR = new Creator<MealModel>() {
        @Override
        public MealModel createFromParcel(Parcel in) {
            return new MealModel(in);
        }

        @Override
        public MealModel[] newArray(int size) {
            return new MealModel[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(mealtype);
        dest.writeString(healthyness);
        dest.writeString(date);
        dest.writeString(pathtoimage);
        dest.writeByte((byte) (favorised ? 1 : 0));
    }

    // getter方法保持不变
    public String getMealtype() { return mealtype; }
    public String getHealthyness() { return healthyness; }
    public String getPathtoimage() { return pathtoimage; }
    public boolean getFavorised() { return favorised; }
    public String getDate() { return date; }
}

方案1:使用SharedPreferences(适合少量餐食数据)

如果你的应用餐食数量不多(几十条以内),SharedPreferences结合Gson序列化是最简单的方案:

1. 添加Gson依赖

在模块级build.gradle的dependencies中添加:

implementation 'com.google.code.gson:gson:2.10.1'

2. 保存列表到SharedPreferences

// 假设已收集数据并创建MealModel列表
List<MealModel> mealList = new ArrayList<>();
mealList.add(new MealModel("早餐", "健康", "2024-05-20", false, "/storage/emulated/0/Pictures/meal1.jpg"));

// 将列表转为JSON字符串
Gson gson = new Gson();
String mealListJson = gson.toJson(mealList);

// 写入SharedPreferences
SharedPreferences prefs = getContext().getSharedPreferences("MealTrackerPrefs", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putString("meal_list", mealListJson);
editor.apply();

3. 从SharedPreferences读取列表

SharedPreferences prefs = getContext().getSharedPreferences("MealTrackerPrefs", Context.MODE_PRIVATE);
String mealListJson = prefs.getString("meal_list", "[]");

Gson gson = new Gson();
Type type = new TypeToken<List<MealModel>>() {}.getType();
List<MealModel> mealList = gson.fromJson(mealListJson, type);

// 用该列表初始化RecyclerView适配器

方案2:使用Room数据库(推荐,适合大量/结构化数据)

如果需要对餐食数据做查询、排序,或者数据量较大,Room是Android官方推荐的本地结构化存储方案:

1. 添加Room依赖

在模块级build.gradle的dependencies中添加:

def room_version = "2.6.1"

implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"

2. 修改MealModel为Room实体类

添加Room注解,将类映射为数据库表:

import androidx.room.Entity;
import androidx.room.PrimaryKey;

@Entity(tableName = "meals")
public class MealModel {
    @PrimaryKey(autoGenerate = true)
    private int id; // 新增主键,用于唯一标识每条数据
    String mealtype;
    String healthyness;
    String date;
    String pathtoimage;
    boolean favorised;

    // 构造方法去掉id(由Room自动生成)
    public MealModel(String mealtype, String healthyness, String date, boolean favorised, String pathtoimage) {
        this.mealtype = mealtype;
        this.healthyness = healthyness;
        this.date = date;
        this.favorised = favorised;
        this.pathtoimage = pathtoimage;
    }

    // 新增id的getter和setter
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }

    // 其他getter方法保持不变
    public String getMealtype() { return mealtype; }
    public String getHealthyness() { return healthyness; }
    public String getPathtoimage() { return pathtoimage; }
    public boolean getFavorised() { return favorised; }
    public String getDate() { return date; }
}

3. 创建Room Dao接口

定义数据库操作方法:

import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.Query;
import java.util.List;

@Dao
public interface MealDao {
    // 插入单条餐食
    @Insert
    void insertMeal(MealModel meal);

    // 插入多条餐食
    @Insert
    void insertAllMeals(List<MealModel> meals);

    // 查询所有餐食
    @Query("SELECT * FROM meals")
    List<MealModel> getAllMeals();

    // 按日期倒序查询餐食
    @Query("SELECT * FROM meals ORDER BY date DESC")
    List<MealModel> getMealsSortedByDate();
}

4. 创建Room数据库类

用单例模式避免重复创建数据库实例:

import androidx.room.Database;
import androidx.room.RoomDatabase;

@Database(entities = {MealModel.class}, version = 1)
public abstract class MealDatabase extends RoomDatabase {
    public abstract MealDao mealDao();

    private static volatile MealDatabase INSTANCE;

    public static MealDatabase getDatabase(final Context context) {
        if (INSTANCE == null) {
            synchronized (MealDatabase.class) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
                            MealDatabase.class, "meal_database")
                            .build();
                }
            }
        }
        return INSTANCE;
    }
}

5. 保存餐食到Room数据库

注意:Room操作不能在主线程执行,推荐用Coroutine处理:

saveBtn.setOnClickListener(view12 -> {
    // 从控件收集数据
    String mealType = view.findViewById(R.id.mealType_textView).getEditableText().toString();
    String healthyness = "..."; // 从对应控件获取
    String date = "...";
    boolean favorised = false; // 根据开关状态获取
    String imagePath = "..."; // 图片本地路径

    MealModel newMeal = new MealModel(mealType, healthyness, date, favorised, imagePath);

    // 用Coroutine在IO线程执行数据库操作
    CoroutineScope scope = CoroutineScope(Dispatchers.IO);
    scope.launch {
        MealDatabase db = MealDatabase.getDatabase(getContext());
        db.mealDao().insertMeal(newMeal);
        // 切换回主线程提示保存成功
        withContext(Dispatchers.Main) {
            Toast.makeText(getContext(), "餐食已保存", Toast.LENGTH_SHORT).show();
        }
    }
});

6. 从Room读取餐食列表

// 在Fragment初始化时读取数据
CoroutineScope scope = CoroutineScope(Dispatchers.IO);
scope.launch {
    MealDatabase db = MealDatabase.getDatabase(getContext());
    List<MealModel> mealList = db.mealDao().getAllMeals();
    // 切换到主线程更新RecyclerView
    withContext(Dispatchers.Main) {
        MealAdapter adapter = new MealAdapter(mealList);
        recyclerView.setAdapter(adapter);
    }
}

方案3:本地文件存储(自定义JSON文件)

也可以将列表序列化为JSON字符串,保存到应用内部存储的文件中:

保存列表到文件

private void saveMealListToFile(List<MealModel> mealList) {
    try {
        FileOutputStream fos = getContext().openFileOutput("meals.json", Context.MODE_PRIVATE);
        Gson gson = new Gson();
        String json = gson.toJson(mealList);
        fos.write(json.getBytes());
        fos.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

从文件读取列表

private List<MealModel> loadMealListFromFile() {
    List<MealModel> mealList = new ArrayList<>();
    try {
        FileInputStream fis = getContext().openFileInput("meals.json");
        BufferedReader br = new BufferedReader(new InputStreamReader(fis));
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        fis.close();
        Gson gson = new Gson();
        Type type = new TypeToken<List<MealModel>>() {}.getType();
        mealList = gson.fromJson(sb.toString(), type);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return mealList;
}

选择建议

  • 数据量小(几十条以内):优先用SharedPreferences,实现简单
  • 需要结构化存储、查询排序或数据量大:选Room数据库,长期维护更方便
  • 自定义文件存储适合需要完全控制存储逻辑的场景,但需自行处理异常和版本兼容

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 04:05:15