Android:如何使 Kotlin 中所有对象列表的类型转换器(用于 Room)通用

Posted

技术标签:

【中文标题】Android:如何使 Kotlin 中所有对象列表的类型转换器(用于 Room)通用【英文标题】:Android: How to make type converters (for Room) generic for all List of objects in Kotlin 【发布时间】:2017-10-05 11:59:36 【问题描述】:

我在我的项目中使用 Room 作为本地数据库解决方案。 对于某个对象类型的每个列表,我已将类型转换器添加到项目中,因此类型转换器看起来像这样:

@TypeConverter
fun convertListToString(video: List<VideoType>): String 

    val videoArray = arrayOfNulls<VideoType>(video.size)
    for (i in 0..video.size - 1) 
        videoArray[i] = video[i]
    
    var str = ""
    val gson = Gson()
    for (i in videoArray.indices) 
        val jsonString = gson.toJson(videoArray[i])
        str = str + jsonString
        if (i < videoArray.size - 1) 
            str = str + strSeparator
        
    

    return str


@TypeConverter
fun convertStringToList(videoString: String): List<VideoType> 

    val videoArray = videoString.split(strSeparator.toRegex()).dropLastWhile  it.isEmpty() .toTypedArray()
    val videos = ArrayList<VideoType>()
    val gson = Gson()
    for (i in 0 until videoArray.size - 1) 
        videos.add(gson.fromJson(videoArray[i], VideoType::class.java))
    

    return videos

唯一的问题是我有一大堆需要转换的不同类型的列表,所以目前我只是为每种类型复制这段代码。我想使用泛型,但到目前为止还没有弄清楚如何去做。

例如使用类似的东西:

@TypeConverter
inline fun <reified T> convertStringToList(string: String): List<T> 
    val objectArray = string.split(strSeparator.toRegex()).dropLastWhile  it.isEmpty() .toTypedArray()
    val objects = ArrayList<T>()
    val gson = Gson()
    for (i in 0 until objectArray.size - 1) 
        objects.add(gson.fromJson(objectArray[i], T::class.java))
    
    return objects

不起作用并导致 android Studio 出现编译错误,告诉我一个错误提示:类型转换器必须是公共的

任何人知道如何为我的 Room TypeConverter 使用泛型?

【问题讨论】:

很好奇你是否能够解决这个问题。如果是这样,您介意为其他人回答您的问题吗? @fawaad 嗨..不,我无法以通用方式解决它。我也很好奇是否有人找到了方法...... 我也有同样的问题,如果你解决了,请发布你的解决方案 @SaurabhKhare 尚未找到通用解决方案。到目前为止需要为每个列表添加类型转换器:( 嗨,如果您不介意的话,您可以在 GitHub 存储库中分享相关代码,我想运行并测试它。 @RikvanVelzen 【参考方案1】:

这样的东西不能用于模板吗?

abstract class Converters<T> 

    @TypeConverter
    fun mapListToString(value: List<T>): String 
        val gson = Gson()
        val type = object : TypeToken<List<T>>() .type
        return gson.toJson(value, type)
    

    @TypeConverter
    fun mapStringToList(value: String): List<T> 
        val gson = Gson()
        val type = object : TypeToken<List<T>>() .type
        return gson.fromJson(value, type)
    


// create 
class UserConverter : Converters<User>()

// usage
@TypeConverters(UserConverter::class)
abstract class TestDatabase : RoomDatabase() 
    abstract fun userDao(): UserDao


或者从当前示例中,如果我这样做会怎样

@TypeConverter
fun <T> mapStringToList(inputString: String): List<T> 
    val array = inputString
        .split(strSeparator.toRegex())
        .dropLastWhile  it.isEmpty() 
        .toTypedArray()
    val result = mutableListOf<T>()
    val gson = Gson()
    // ? ----
    val type = object : TypeToken<List<T>>() .type
    // ----
    return array.fold(result)  acc, item ->
        acc.add(gson.fromJson(item, type))
        acc
    

【讨论】:

【参考方案2】:

我也有同样的问题。仅用于转换 listToString 的部分解决方案

@TypeConverter
@JvmStatic
fun listToString(list: List<*>?): String? = list.let 
    val gson = GsonBuilder().serializeNulls().create()

    gson.toJson(it)

【讨论】:

【参考方案3】:

我尝试使用标记接口将类转换为标记,反之亦然,但没有成功。我尝试了大多数 Java 扩展的 Object 类,但它不起作用。我认为答案是您不能在房间类型转换器中使用 Generic。

【讨论】:

【参考方案4】:

嗯,基本上类型转换器的主要思想是数据库不能将对象作为参数读取。所以你必须有两种方法第一种是在数据库中使用连接关系手动完成,或者你可以使用类型转换器。 类型转换器如何工作? 这很简单,只需将您的对象转换为 JSON 字符串并将其保存为字符串。 在您的问题中,您必须在实体之前添加注释

private class YourDTO(
        @TypeConverters(DateConverter.class)
         Date date

在 DateConverter 类中

@TypeConverter
public static Long toTimestamp(Date date) 
    return date == null ? null : date.getTime();

【讨论】:

【参考方案5】:

我刚刚对此进行了测试,似乎可以满足您的需求。您可以根据需要调整功能,但这应该可以帮助您: 参考https://kotlinlang.org/docs/reference/generics.html#generic-functions

fun test() 
        val list1 = listOf("1", "2")
        val list2 = listOf(1, 2, 3)

        list1.convertToString()
        list2.convertToString()
    

    fun List<Any>.convertToString(): String 
        var result = ""
        val gson = Gson()
        for (i in 0.. size - 1) 
            result += gson.toJson(get(i), get(i).javaClass)
        
        return result
    

【讨论】:

这可能会解决将任何类型的列表转换为字符串的技巧,但它不能解决将 typeConvertors 与 Room 一起使用的问题。如果我在列表上使用扩展名,我想将其转换为字符串(即使使用@typeConverter 对其进行注释)房间; “无法弄清楚如何将此字段保存到数据库中。”

以上是关于Android:如何使 Kotlin 中所有对象列表的类型转换器(用于 Room)通用的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Android 的 Kotlin 中使用 GSON 将 JSON 对象转换为 JSON 数组

如何使 Android 的 Singleton 对象持久化

如何在 Kotlin Android 中将字符串转换为 JSON 对象 [重复]

如何从 Firebase android kotlin 获取所有具有特定价值的孩子?

如何使reyclerview项目可见并且不留空间--Kotlin?

android中通过kotlin使用WebView