在Java中按正确顺序向Set<String>添加项目

3

我正在创建一款歌曲播放应用程序。我有一个Set集合,保存在SharedPreferences中。我想添加和删除文件名,并保持它们与我添加它们的顺序相同,例如:

recentsp = getSharedPreferences("recentkey", Context.MODE_PRIVATE);

    recent = recentsp.getStringSet("recent", recent);
    recentedited = recent;

    if (recentedited.contains(string) {
        recentedited.remove(string);
        Log.i(TAG, "Recent exists, removing song");
        SharedPreferences.Editor editor = recentsp.edit();
        editor.clear();
        editor.putStringSet("recent", recentedited);
        editor.commit();
    }

        recentedited.add(string);
    Log.i(TAG, "adding song to recent");
        SharedPreferences.Editor editor = recentsp.edit();
        editor.clear();
        editor.putStringSet("recent", recentedited);
        editor.commit();

但是当我在ListView中查看它们时,问题就出现了。我希望它们按照我添加的顺序排列,这样我就可以有一个最近播放的部分,但有时它们根本不动,或者可能会出现在开头。它似乎是随机的。我错过了什么吗?
编辑:
在初始化步骤中,我通过执行以下操作来确保SharedPreferences不为空...
编辑:
即使使用LinkedHashSet,我仍然无法获得正确的排序。我只有在SharedPreferences为空时才调用此函数,因此我不太确定如何确保我正在使用LinkedHashSet。
        recentsp = getSharedPreferences("recentkey", Context.MODE_PRIVATE);
    recent = recentsp.getStringSet("recent", null);
    if (recent == null) {

        recent = new LinkedHashSet<String>();
        SharedPreferences.Editor editor = recentsp.edit();
        editor.clear();
        editor.putStringSet("recent", recent);
        editor.commit();
    }

可能性很大;从 API 看来,维护任何类型的顺序可能不是可用的功能。但你应该 首先 修改你的代码,避免做文档明确告诉你不要做的事情,然后再解决这个 bug。 - Louis Wasserman
我刚刚编辑了问题,包括我如何实现集合。 - MJDude
HashSet 具有未定义的、类似随机的排序。如果您需要排序,请使用 LinkedHashSet;看看是否有所帮助。但是,当您特别不关心顺序时,可以使用 HashSet - Louis Wasserman
你会如何复制它? - MJDude
recentedited = new LinkedHashSet<String>(recent)可以实现你想要的效果。recentedited = recent没有任何有用的作用。 - Louis Wasserman
显示剩余6条评论
3个回答

6
如果你正在寻找一个实现了Set接口并且保留插入顺序的类,那么请使用LinkedHashSet替换掉HashSet。所有标准的Set行为都保持不变,在此基础上还增加了插入顺序的迭代。
根据相关JavaDoc:
“哈希表和链接列表是Set接口的实现,具有可预测的迭代顺序。这个实现与HashSet不同之处在于它维护了一个双向链表,该链表穿过所有条目。这个链接列表定义了迭代顺序,即元素插入到集合中的顺序(插入顺序)。请注意,如果一个元素被重新插入到集合中,插入顺序不会受到影响。(如果在调用s.add(e)之前,s.contains(e)将立即返回true,则表示元素e被重新插入到集合s中)。
这个实现避免了HashSet提供的无序、混乱的排序方式,而不会像TreeSet一样增加成本。它可以用来产生一个具有原始集合相同顺序的集合副本,而不管原始集合的实现方式如何。”

我刚刚编辑了我的答案并进行了更改,但似乎仍然没有保留我的顺序。 - MJDude
@MJDude,与其尝试将每个歌曲标题保存为单独的“SharedPreference”,为什么不将列表保存为单个值呢?将播放列表保存为不同类型的资源可能会更自然;我并不是要批评,但它实际上不是控制应用程序在运行时如何运作的设置值 - 它只是一些已保存状态。这样,您就可以完全控制所需的排序方式了。 - Sean Mickey
我已经将歌曲标题放入一个列表中了。但是您还有什么其他建议来保存它? - MJDude
与其创建一个Set<String>,其中每个String都是单独的歌曲标题,然后将该Set作为(一组)SharedPreference值添加,我试图描述的是仅使用单个String作为单个Preference,并构造该单个值,使其包含由分隔符分隔的所有歌曲标题。如果您选择分号作为分隔符,则该单个Preference的值最终会变成类似于:“Song Title 1;Song Title 2;Very, Very Long Song Title 3;Song Title 4”等。 - Sean Mickey
谢谢,那就是我所做的! - MJDude

2
我有一个Set,我将其保存在SharedPreferences中。我想要添加和删除文件名,并保持它们的顺序不变。
这是不可能的。您无法控制Set实现,并且没有要求Set必须有序。您的选择是:
1. 不要担心顺序 2. 不要使用SharedPreferences中的字符串集,而是将值存储在单个字符串中(例如,编码为JSON) 3. 不要使用SharedPreferences,而是使用其他数据存储选项(例如,SQLite数据库,JSON文件)

0
也许只需使用 ArrayList 而不是 Set - 看起来您已经有了代码来确保如果项目已经在集合中,则将其删除并添加 - 该模式应该适用于 ArrayList。
如果您需要将列表序列化为首选项的代码,这个旧问题有一个示例 Save ArrayList to SharedPreferences 或者使用类似 GSON 的东西来存储和检索 Store a List or Set in SharedPreferences

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