Android: 如何将地图保存到SharedPreferences?

4
我需要以以下方式将数据保存到SharedPreferences中:

我有这样一个对象:

{
    "days": [
        {
            "exercises": [
                {
                    "name": "Bench Press",
                    "sets": 3,
                    "reps": 8
                },
                {
                    "name": "Skull Crushers",
                    "sets": 3,
                    "reps": 8
                },
                {
                    "name": "Flys",
                    "sets": 3,
                    "reps": 8
                }
            ]
        },
        {
            "exercises": [
                {
                    "name": "Bench Press",
                    "sets": 3,
                    "reps": 8
                },
                {
                    "name": "Skull Crushers",
                    "sets": 3,
                    "reps": 8
                },
                {
                    "name": "Flys",
                    "sets": 3,
                    "reps": 8
                }
            ]
        }
    ]
}

我需要从对象中提取并添加到对象中。我知道你不能将地图保存到SharedPreferences中。我开始考虑使用ObjectOutputStream,但不确定是否在内存中使用它最好。我想知道我的最佳选择是什么。

编辑:根据Advice-Dog的建议,我认为最好使用gson。那么这是否意味着,当我想要(例如)将另一个练习添加到“days”的第二个索引时,我将首先从首选项中获取对象,将其从gson转换为对象,然后添加该练习,然后再将其转换回gson,最后覆盖首选项?我不是说这样做不好,只是想知道这是否应该这样做,以及是否可行。


这个数据结构存在问题,即无法区分日期 - 而SharedPreferences更适合用于保存应用程序设置(简单数据),而不是被滥用作为数据库。 - Martin Zeitler
3个回答

8

在Android中保存更复杂的类型时,我建议使用gson。Gson是谷歌的JSON解析库,即使您不使用JSON,也可以将您的Objects转换为JSON字符串,并轻松存储。

例如,您可以像这样将您的Objects列表转换为String

val list : List<MyObject>  // ... add items to your list

// Convert to JSON

val string = gson.toJson(list)

// Store it into Shared Preferences
preferences.putString("list", string).apply()

然后你可以轻松地将它重新放回到一个列表中,就像这样。
// Fetch the JSON 

val string = preferences.getString("list", "")

// Convert it back into a List

val list: List<MyObject> = gson.fromJson(string, object : TypeToken<List<MyObject>>() {}.type)

只是一个问题。这是否意味着每当我想向对象添加一个值时,我将首先将 json 转换为对象,然后添加该值,然后再将其转换回 json,然后保存到先前的偏好中? - Slaknation
@BUInvent 是的。这听起来可能有些浪费,但完全没问题。GSON非常快,SharedPreferences也是如此。您还可以保留本地副本,更新它并保存它。因此,您不会不断地读取它,但这取决于您的使用情况。 - advice

1
使用JSON是最好的解决方案,但这里还有另一种解决方法(只是为了增加解决问题的方式):
您可以像这样使用共享首选项键:
for((dayIndex, day) in days.withIndex)
    for((exeIndex, exe) in day)
       for((key, value) in exe)
          addExercise(day = dayIndex, exercise = exeIndex, key = key, value = value)


fun addExercise(day: String, exercise: String, key: String, value: String) = 
     preferences.putString("day${day}_exe${exercise}_${key}", value).apply()           

那么你可以像这样从第二天获取第一次练习的名称

val first_exercise_second_day = preferences.getString("day2_exe1_name")

你可以这样向第三天添加一个练习:

 addExercise(day = "3", exercise = "1", key = "name", value = "Flys")
 addExercise(day = "3", exercise = "1", key = "sets", value = "5")
 addExercise(day = "3", exercise = "1", key = "reps", value = "3")

但是如果要找到空的日期或者空的练习编号,你需要获取所有共享偏好的键,并使用正则表达式或循环来查找。


1

您可以使用Google的库==> Gson,将其添加到Gradle依赖项中即可。

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

你可以使用这个库将对象转换为JSON字符串,然后将其保存为共享偏好设置中的字符串。当你从偏好设置中获取字符串时,你可以将字符串转换为对象。
将JSON转换为模型。
    /*type of model*/=new Gson().fromJson(/*json string*/,/*type of model*/)

将模型转换为JSON字符串。
 new Gson().toJson(/*model you want to convert */)===> return String

必须为JSON建立相同的层次结构,否则在转换过程中会出现问题。

您的JSON模型必须像这个模型一样。

  public class JSONModel implements Serializable {


    @SerializedName("days")
    private List<Day> mDays;

    public List<Day> getDays() {
        return mDays;
    }

    public void setDays(List<Day> days) {
        mDays = days;
    }

    public class Day {

        @SerializedName("exercises")
        private List<Exercise> mExercises;

        public List<Exercise> getExercises() {
            return mExercises;
        }

        public void setExercises(List<Exercise> exercises) {
            mExercises = exercises;
        }

    }
    public class Exercise {

        @SerializedName("name")
        private String mName;
        @SerializedName("reps")
        private Long mReps;
        @SerializedName("sets")
        private Long mSets;

        public String getName() {
            return mName;
        }

        public void setName(String name) {
            mName = name;
        }

        public Long getReps() {
            return mReps;
        }

        public void setReps(Long reps) {
            mReps = reps;
        }

        public Long getSets() {
            return mSets;
        }

        public void setSets(Long sets) {
            mSets = sets;
        }

    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接