Java Android Room数据库:如何处理实体中的Arraylist?

Java Android Room数据库:如何处理实体中的Arraylist?,java,android,android-room,Java,Android,Android Room,我刚刚实现了离线数据保存空间。但在实体类中,我得到以下错误: Error:(27, 30) error: Cannot figure out how to save this field into database. You can consider adding a type converter for it. 课程安排如下: @Entity(tableName = "firstPageData") public class MainActivityData {

我刚刚实现了离线数据保存空间。但在实体类中,我得到以下错误:

Error:(27, 30) error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
课程安排如下:

@Entity(tableName = "firstPageData")
public class MainActivityData {

    @PrimaryKey
    private String userId;

    @ColumnInfo(name = "item1_id")
    private String itemOneId;

    @ColumnInfo(name = "item2_id")
    private String itemTwoId;

    // THIS IS CAUSING THE ERROR... BASICALLY IT ISN'T READING ARRAYS
    @ColumnInfo(name = "mylist_array")
    private ArrayList<MyListItems> myListItems;

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public ArrayList<MyListItems> getMyListItems() {
        return myListItems;
    }

    public void setCheckListItems(ArrayList<MyListItems> myListItems) {
        this.myListItems = myListItems;
    }

}
@实体(tableName=“firstPageData”)
公共类MainActivityData{
@主键
私有字符串用户标识;
@ColumnInfo(name=“item1\u id”)
私有字符串itemOneId;
@ColumnInfo(name=“item2\u id”)
私有字符串itemTwoId;
//这是导致错误的原因…基本上不是读取数组
@ColumnInfo(name=“mylist\u数组”)
私人ArrayList myListItems;
公共字符串getUserId(){
返回用户标识;
}
public void setUserId(字符串userId){
this.userId=userId;
}
公共数组列表getMyListItems(){
返回我的列表项;
}
public void setCheckListItems(ArrayList myListItems){
this.myListItems=myListItems;
}
}
所以基本上我想把ArrayList保存在数据库中,但是我找不到任何与之相关的东西。您能指导我如何使用Room保存阵列吗

注意:MyListItems Pojo类包含2个字符串(截至目前)

提前感谢。

选项1:让
MyListItems
成为
@实体
,就像
MainActivityData
一样
MyListItems
将设置一个
@ForeignKey
返回到
MainActivityData
。但是,在这种情况下,
MainActivityData
不能有
私有数组列表myListItems
,因为在文件室中,实体不引用其他实体。但是,视图模型或类似的POJO构造可以具有
MainActivityData
及其关联的
ArrayList

选项2:设置一对
@TypeConverter
方法,将
ArrayList
转换为一些基本类型(例如
String
,例如使用JSON作为存储格式)。现在,
MainActivityData
可以直接拥有它的
ArrayList
。但是,
MyListItems
没有单独的表,因此您无法很好地查询
MyListItems

就是专门为此而设计的。在您的情况下,您可以使用下面给出的代码片段在DB中存储数据

public class Converters {
    @TypeConverter
    public static ArrayList<String> fromString(String value) {
        Type listType = new TypeToken<ArrayList<String>>() {}.getType();
        return new Gson().fromJson(value, listType);
    }

    @TypeConverter
    public static String fromArrayList(ArrayList<String> list) {
        Gson gson = new Gson();
        String json = gson.toJson(list);
        return json;
    }
}

更多信息

具有与上述相同的错误消息。 我想补充一点:如果您在@Query中收到此错误消息,您应该在@Query注释上方添加@TypeConverters

例如:

@TypeConverters(DateConverter.class)
@Query("update myTable set myDate=:myDate  where id = :myId")
void updateStats(int myId, Date myDate);


Kotlin类型转换器的版本:

 class Converters {

    @TypeConverter
    fun listToJson(value: List<JobWorkHistory>?) = Gson().toJson(value)

    @TypeConverter
    fun jsonToList(value: String) = Gson().fromJson(value, Array<JobWorkHistory>::class.java).toList()
}

这就是我处理列表转换的方式

public class GenreConverter {
@TypeConverter
public List<Integer> gettingListFromString(String genreIds) {
    List<Integer> list = new ArrayList<>();

    String[] array = genreIds.split(",");

    for (String s : array) {
       if (!s.isEmpty()) {
           list.add(Integer.parseInt(s));
       }
    }
    return list;
}

@TypeConverter
public String writingStringFromList(List<Integer> list) {
    String genreIds = "";
    for (int i : list) {
        genreIds += "," + i;
    }
    return genreIds;
}}
下面是kotlin的一个相同实现

class GenreConverter {
@TypeConverter
fun gettingListFromString(genreIds: String): List<Int> {
    val list = mutableListOf<Int>()

    val array = genreIds.split(",".toRegex()).dropLastWhile {
        it.isEmpty()
    }.toTypedArray()

    for (s in array) {
        if (s.isNotEmpty()) {
            list.add(s.toInt())
        }
    }
    return list
}

@TypeConverter
fun writingStringFromList(list: List<Int>): String {
    var genreIds=""
    for (i in list) genreIds += ",$i"
    return genreIds
}}
class-genrecoverter{
@类型转换器
有趣的gettingListFromString(genreIds:String):列表{
val list=mutableListOf()
val array=genreIds.split(“,”.toRegex()).dropLastWhile{
它是空的
}.toTypedArray()
用于(数组中的个){
如果(s.isNotEmpty()){
list.add(s.toInt())
}
}
返回列表
}
@类型转换器
有趣的writingStringFromList(list:list):字符串{
var genreIds=“”
对于(列表中的i)genreIds+=“,$i”
返回genreIds
}}

使用room的官方解决方案,@Embedded annotation:

@Embedded(prefix = "mylist_array") private ArrayList<MyListItems> myListItems
@Embedded(prefix=“mylist\u array”)私有数组列表mylistems

添加
@TypeConverters
,将converter类作为参数


到数据库&到Dao类,使我的查询工作

此答案使用Kotin按逗号分割并构造逗号分隔的字符串。逗号需要放在除最后一个元素之外的所有元素的末尾,因此这也将处理单个元素列表

object StringListConverter {
        @TypeConverter
        @JvmStatic
        fun toList(strings: String): List<String> {
            val list = mutableListOf<String>()
            val array = strings.split(",")
            for (s in array) {
                list.add(s)
            }
            return list
        }

        @TypeConverter
        @JvmStatic
        fun toString(strings: List<String>): String {
            var result = ""
            strings.forEachIndexed { index, element ->
                result += element
                if(index != (strings.size-1)){
                    result += ","
                }
            }
            return result
        }
    }
对象StringListConverter{
@类型转换器
@JvmStatic
乐趣列表(字符串:字符串):列表{
val list=mutableListOf()
val数组=字符串。拆分(“,”)
用于(数组中的个){
列表。添加
}
返回列表
}
@类型转换器
@JvmStatic
趣味toString(字符串:列表):字符串{
var result=“”
strings.foreachinedexed{index,element->
结果+=元素
if(索引!=(strings.size-1)){
结果+=“,”
}
}
返回结果
}
}

就内存分配而言,Json转换的伸缩性不好。我更愿意选择类似于上面的响应,并带有一些空值

class Converters {
    @TypeConverter
    fun stringAsStringList(strings: String?): List<String> {
        val list = mutableListOf<String>()
        strings
            ?.split(",")
            ?.forEach {
                list.add(it)
            }

        return list
    }

    @TypeConverter
    fun stringListAsString(strings: List<String>?): String {
        var result = ""
        strings?.forEach { element ->
            result += "$element,"
        }
        return result.removeSuffix(",")
    }
}
类转换器{
@类型转换器
有趣的字符串字符串(字符串:字符串?):列表{
val list=mutableListOf()
串
?分割(“,”)
?forEach{
列表。添加(it)
}
返回列表
}
@类型转换器
有趣的字符串列表字符串(字符串:列表?):字符串{
var result=“”
字符串?.forEach{element->
结果+=“$element,”
}
返回结果。removeSuffix(“,”)
}
}

对于简单的数据类型,可以使用上述方法,否则对于复杂的数据类型,Room提供了更好的
列表
转换器版本

class StringListConverter {
    @TypeConverter
    fun fromString(stringListString: String): List<String> {
        return stringListString.split(",").map { it }
    }

    @TypeConverter
    fun toString(stringList: List<String>): String {
        return stringList.joinToString(separator = ",")
    }
}
类StringListConverter{
@类型转换器
趣味fromString(stringListString:String):列表{
返回stringListString.split(“,”).map{it}
}
@类型转换器
funtostring(stringList:List):String{
返回stringList.joinToString(分隔符=“,”)
}
}

以下是将customObject类型添加到Room DB表的示例。

添加一个类型转换器很容易,我只需要一个可以将对象列表转换为字符串的方法,以及一个可以实现相反操作的方法。我用gson来做这个

public class Converters {

    @TypeConverter
    public static String MyListItemListToString(List<MyListitem> list) {
        Gson gson = new Gson();
        return gson.toJson(list);
    }

    @TypeConverter
    public static List<Integer> stringToMyListItemList(@Nullable String data) {
        if (data == null) {
            return Collections.emptyList();
        }

        Type listType = new TypeToken<List<MyListItem>>() {}.getType();

        Gson gson = new Gson();
        return gson.fromJson(data, listType);
    }
}
公共类转换器{
@类型转换器
公共静态字符串MyListItemListToString(列表){
Gson Gson=新的Gson();
返回gson.toJson(列表);
}
@类型转换器
公共静态列表stringToMyListItemList(@Nullable String data){
如果(数据==null){
return Collections.emptyList
object StringListConverter {
        @TypeConverter
        @JvmStatic
        fun toList(strings: String): List<String> {
            val list = mutableListOf<String>()
            val array = strings.split(",")
            for (s in array) {
                list.add(s)
            }
            return list
        }

        @TypeConverter
        @JvmStatic
        fun toString(strings: List<String>): String {
            var result = ""
            strings.forEachIndexed { index, element ->
                result += element
                if(index != (strings.size-1)){
                    result += ","
                }
            }
            return result
        }
    }
class Converters {
    @TypeConverter
    fun stringAsStringList(strings: String?): List<String> {
        val list = mutableListOf<String>()
        strings
            ?.split(",")
            ?.forEach {
                list.add(it)
            }

        return list
    }

    @TypeConverter
    fun stringListAsString(strings: List<String>?): String {
        var result = ""
        strings?.forEach { element ->
            result += "$element,"
        }
        return result.removeSuffix(",")
    }
}
class StringListConverter {
    @TypeConverter
    fun fromString(stringListString: String): List<String> {
        return stringListString.split(",").map { it }
    }

    @TypeConverter
    fun toString(stringList: List<String>): String {
        return stringList.joinToString(separator = ",")
    }
}
public class Converters {

    @TypeConverter
    public static String MyListItemListToString(List<MyListitem> list) {
        Gson gson = new Gson();
        return gson.toJson(list);
    }

    @TypeConverter
    public static List<Integer> stringToMyListItemList(@Nullable String data) {
        if (data == null) {
            return Collections.emptyList();
        }

        Type listType = new TypeToken<List<MyListItem>>() {}.getType();

        Gson gson = new Gson();
        return gson.fromJson(data, listType);
    }
}
@TypeConverters(Converters.class)

public final ArrayList<MyListItem> myListItems;
 import androidx.room.TypeConverter
 import com.google.gson.Gson 
 import com.google.gson.reflect.TypeToken
 class IntArrayListConverter {
     @TypeConverter
     fun fromString(value: String): List<Int> {
         val type = object: TypeToken<List<Int>>() {}.type
         return Gson().fromJson(value, type)
     }

     @TypeConverter
     fun fromArrayList(list: List<Int>): String {
         val type = object: TypeToken<List<Int>>() {}.type
         return Gson().toJson(list, type)
     } 
}
@Database(entities = [MyEntity::class], version = 1, exportSchema = false)
@TypeConverters(IntArrayListConverter::class)
abstract class MyDatabase : RoomDatabase() {
 private static final Migration MIGRATION_1_2 = new Migration(1, 2) {
    @Override
    public void migrate(@NonNull SupportSQLiteDatabase database) {
        // Since we didn't alter the table, there's nothing else to do here.
        database.execSQL("ALTER TABLE "+  Collection.TABLE_STATUS  + " ADD COLUMN deviceType TEXT;");
        database.execSQL("ALTER TABLE "+  Collection.TABLE_STATUS  + " ADD COLUMN inboxType TEXT;");
    }
};
 @Query("SELECT * FROM business_table")
 abstract List<DatabaseModels.Business> getBusinessInternal();


 @Transaction @Query("SELECT * FROM business_table")
 public ArrayList<DatabaseModels.Business> getBusiness(){
        return new ArrayList<>(getBusinessInternal());
 }
 @TypeConverter
        public String fromValuesToList(ArrayList<**YourClassName**> value) {
            if (value== null) {
                return (null);
            }
            Gson gson = new Gson();
            Type type = new TypeToken<ArrayList<**YourClassName**>>() {}.getType();
            return gson.toJson(value, type);
        }
    
        @TypeConverter
        public ArrayList<**YourClassName**> toOptionValuesList(String value) {
            if (value== null) {
                return (null);
            }
            Gson gson = new Gson();
            Type type = new TypeToken<List<**YourClassName**>>() {
            }.getType();
            return gson.fromJson(value, type);
        }
@Entity....
data class bar(
...
val foos: ArrayList<Int>)
@Entity(tablename="bar_foo", primaryKeys=["fooId", "barId"])
data class barFoo(val barId: Int, val fooId: Int)
@Entity
public class MainActivityData {
    @PrimaryKey
    private String userId;
    private String itemOneId;
    private String itemTwoId;
}

@Entity
public class MyListItem {
    @PrimaryKey
    public int id;
    public String ownerUserId;
    public String text;
}

/* This is the class we use to define our relationship,
   which will also be used to return our query results.
   Note that it is not defined as an @Entity */
public class DataWithItems {
    @Embedded public MainActivityData data;
    @Relation(
        parentColumn = "userId"
        entityColumn = "ownerUserId"
    )
    public List<MyListItem> myListItems;
}

/* This is the DAO interface where we define the queries.
   Even though it looks like a single SELECT, Room performs
   two, therefore the @Transaction annotation is required */
@Dao
public interface ListItemsDao {
    @Transaction
    @Query("SELECT * FROM MainActivityData")
    public List<DataWithItems> getAllData();
}
apply plugin: 'kotlinx-serialization'

dependencies {
   ...
   implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1"
}
class Converters {
   @TypeConverter
   fun fromList(value : List<String>) = Json.encodeToString(value)

   @TypeConverter
   fun toList(value: String) = Json.decodeFromString<List<String>>(value)
}
@TypeConverters(Converters::class)
abstract class YourDatabase: RoomDatabase() {...}
 class Converters {

    @TypeConverter
    fun listToJsonString(value: List<YourModel>?): String = Gson().toJson(value)

    @TypeConverter
    fun jsonStringToList(value: String) = Gson().fromJson(value, Array<YourModel>::class.java).toList()
}
@Database(entities = [YourEntity::class], version = 1)
@TypeConverters(Converters::class)
abstract class YourDatabase : RoomDatabase() {
     abstract fun yourDao(): YourDao
}
@Entity(tableName = "example_database_table") 
data class YourEntity(
  @PrimaryKey(autoGenerate = true) val id: Long = 0,
  @ColumnInfo(name = "your_model_list") var yourModelList: List<YourModel>,
)