【问题标题】:Android: How to make type converters (for Room) generic for all List of objects in KotlinAndroid:如何使 Kotlin 中所有对象列表的类型转换器(用于 Room)通用
【发布时间】: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

标签: android generics kotlin android-room


【解决方案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 对其进行注释)房间; “无法弄清楚如何将此字段保存到数据库中。”
          猜你喜欢
          • 2019-03-14
          • 1970-01-01
          • 1970-01-01
          • 2019-08-04
          • 2018-06-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-11-19
          相关资源
          最近更新 更多