尝试使用 Android Room Library 缓存 HashSet 时出错

Error while trying to cache a HashSet using Android Room Library

我愿意尝试 Android 的新房间库,但我遇到了以下错误:

Error:(19, 29) error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.

此错误涉及以下 class 成员:

private HashSet<String> fruits;

我有以下 class:

@Entity(tableName = "SchoolLunches")
public class SchoolLunch {

    @PrimaryKey(autoGenerate = true)
    private int lunchId;

    private boolean isFresh;

    private boolean containsMeat;

    private HashSet<String> fruits;

    public int getLunchId() {
        return lunchId;
    }

    public void setLunchId(int lunchId) {
        this.lunchId = lunchId;
    }

    public boolean isFresh() {
        return isFresh;
    }

    public void setFresh(boolean fresh) {
        isFresh = fresh;
    }

    public boolean isContainsMeat() {
        return containsMeat;
    }

    public void setContainsMeat(boolean containsMeat) {
        this.containsMeat = containsMeat;
    }

    public HashSet<String> getFruits() {
        return fruits;
    }

    public void setFruits(HashSet<String> fruits) {
        this.fruits = fruits;
    }

还有一个相对的DAO class:

@Dao
public interface SchoolLunchDAO {

    @Query("SELECT * FROM SchoolLunches")
    List<SchoolLunch> getAll();

    @Insert
    void insertAll(SchoolLunch... schoolLunches);

    @Query("DELETE FROM SchoolLunches")
    void deleteAll();
}

因为我想成为一个非常优秀的开发者,所以我写了一个单元测试如下:

@Test
public void singleEntityTest() {
        HashSet<String> fruitSet = new HashSet<>();
        fruitSet.add("Apple");
        fruitSet.add("Orange");

        SchoolLunch schoolLunch = new SchoolLunch();
        schoolLunch.setContainsMeat(false);
        schoolLunch.setFresh(true);
        schoolLunch.setFruits(fruitSet);

        schoolLunchDAO.insertAll(schoolLunch);

        List<SchoolLunch> schoolLunches = schoolLunchDAO.getAll();
        assertEquals(schoolLunches.size(), 1);

        SchoolLunch extractedSchoolLunch = schoolLunches.get(0);
        assertEquals(false, extractedSchoolLunch.isContainsMeat());
        assertEquals(true, extractedSchoolLunch.isFresh());
        assertEquals(2, extractedSchoolLunch.getFruits().size());
 }

我应该在这里做什么?

What should I do here?

您可以按照错误消息的建议创建 type converter。 Room 不知道如何保留 HashSet<String>Restaurant 或其他任意对象。

第 1 步:确定要将 HashSet<String> 转换成哪种基本类型(例如 String

步骤 #2:写一个 class 和 public static 类型转换方法,用 @TypeConverter 注释,进行转换(例如,HashSet<String>StringStringHashSet<String>),以某种安全的方式(例如,使用 Gson,将 String 格式化为 JSON)

第 3 步:将 @TypeConverters 注释添加到您的 RoomDatabase 或其他范围,以向 Room 介绍您的 @TypeConverter 方法

例如,这里有一对类型转换器方法,用于将 Set<String> to/from 转换为常规 String,使用 JSON 作为 String.

  @TypeConverter
  public static String fromStringSet(Set<String> strings) {
    if (strings==null) {
      return(null);
    }

    StringWriter result=new StringWriter();
    JsonWriter json=new JsonWriter(result);

    try {
      json.beginArray();

      for (String s : strings) {
        json.value(s);
      }

      json.endArray();
      json.close();
    }
    catch (IOException e) {
      Log.e(TAG, "Exception creating JSON", e);
    }

    return(result.toString());
  }

  @TypeConverter
  public static Set<String> toStringSet(String strings) {
    if (strings==null) {
      return(null);
    }

    StringReader reader=new StringReader(strings);
    JsonReader json=new JsonReader(reader);
    HashSet<String> result=new HashSet<>();

    try {
      json.beginArray();

      while (json.hasNext()) {
        result.add(json.nextString());
      }

      json.endArray();
    }
    catch (IOException e) {
      Log.e(TAG, "Exception parsing JSON", e);
    }

    return(result);
  }

我创建了以下 class,现在可以使用了。谢谢您,CommonsWare!

public class Converters {

    private static final String SEPARATOR = ",";

    @TypeConverter
    public static HashSet<String> fromString(String valueAsString) {
        HashSet<String> hashSet = new HashSet<>();
        if (valueAsString != null && !valueAsString.isEmpty()) {
            String[] values = valueAsString.split(SEPARATOR);
            hashSet.addAll(Arrays.asList(values));
        }
        return hashSet;
    }

    @TypeConverter
    public static String hashSetToString(HashSet<String> hashSet) {
        StringBuilder stringBuilder = new StringBuilder();
        for (String currentElement : hashSet) {
            stringBuilder.append(currentElement);
            stringBuilder.append(SEPARATOR);
        }
        return stringBuilder.toString();
    }

}