当前位置: 首页 > 知识库问答 >
问题:

泛型Android和Moshi适配器

毋宸
2023-03-14

我正在尝试使用moshi与我的Android项目,但我遇到了一些问题。

下面是一个精简的JSON示例

{
  "data": [
    {
      "label": "May",
      "schedule_items": [
        {
          "type": "event",
          "item": {
            "foo": "bar",
            "some_prop": 1
          },
          "schedule_item_groups": [
            {
              "label": "Friday May 4th",
              "schedule_items": [
                {
                  "type": "check_in",
                  "item": {
                    "a_different_prop": 15
                  },
                  "schedule_item_groups": null
                },
                {
                  "type": "game",
                  "item": {
                    "yet_another_different_prop": 3598
                  },
                  "schedule_item_groups": null
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

如您所见,它是schedulegroups的列表,在该对象中有一个标签和schedule_items。它是包含3个字段的ScheduleItem数组:

  • type:用于标识项目类型的字符串标签
  • 项目:可以是事件游戏签入
  • schedule_item_groups:schedulegroup,它是更多scheduleitems
  • 的列表

因此,第一个问题是schedulegroup有一个scheduleitems列表,每个项都可以有自己的schedulegroup列表,其中包含更多项。

第二个问题是item字段,它需要实例化为三个类之一:eventgamecheckin

我已经在这方面工作了一段时间,到目前为止,我只能得到一个工作一次,但不是两个。

以下是类的数据(我只包括了item类中的一个):

data class ScheduleGroup(
    val label: String,
    val schedule_items: List<ScheduleItem<Any>>
)
data class ScheduleItem<out T>(
    val type: String,
    val schedule_item_groups: List<ScheduleGroup>
    val item: T
) {
    abstract class Item
}
data class Event(
    val some_prop: Int,
    val foo: String
) : ScheduleItem.Item()

下面是动态泛型类item的工作方式:

@FromJson
fun fromJson(map: Map<*, *>): ScheduleItem<Any> {
    val moshi: Moshi = Moshi.Builder().build()
    val type: String = map["type"] as String
    val itemJson = moshi.adapter(Map::class.java).toJson(map["item"] as Map<*, *>)

    val item = when (type) {
        EventType.EVENT -> moshi.adapter(Event::class.java).fromJson(itemJson)
        EventType.GAME -> moshi.adapter(Game::class.java).fromJson(itemJson)
        EventType.CHECK_IN, EventType.CHECK_OUT ->
            moshi.adapter(CheckIn::class.java).fromJson(itemJson)
        else -> throw Error("Unknown type was found $type")
    }

val scheduleGroupType = Types.newParameterizedType(List::class.java, ScheduleGroup::class.java)
    @Suppress("UNCHECKED_CAST")
    val scheduleGroupJson = moshi.adapter<List<ScheduleGroup>>(scheduleGroupType)
        .toJson(map["schedule_item_groups"] as List<ScheduleGroup>?)

    val list: List<ScheduleGroup>? = moshi
        .adapter<List<ScheduleGroup>>(scheduleGroupType).fromJson(scheduleGroupJson)

    return ScheduleItem(type, list ?: listOf(), item)
}

它将正确创建正确的item类,但当我尝试添加列表 时,我会出现错误,而且无论我做什么,似乎都不能使两者都起作用。

编辑:

我更新了代码,以显示我正在使用什么来尝试反序列化schedule_item_groups,这是一个列表

我得到一个错误:(这是一个不同的错误我以前得到的...)

com.squareup.moshi.jsonDataException:java.lang.IllegalArgumentException:无法将最终java.lang.String字段com.roomroster.mobile_android.data.api.schedule.models.schedulegroup.label设置为$.data[0].schedule_items[1]处的com.squareup.moshi.linkedHashTreemap

共有1个答案

罗昱
2023-03-14

我想出来了一段时间,但我想我可以张贴我所做的,以防它会帮助任何人在未来。

首先,我创建了一个临时中介类,用于在生成泛型数据之前保存数据。

data class ScheduleItem<T>(
    val date: Date,
    val type: String,
    var scheduleGroups: List<ScheduleGroup> = listOf(),
    var item: T
) {
    data class ScheduleItemJson(
        val date: Date,
        val type: String,
        val schedule_item_groups: List<ScheduleGroup>? = listOf(),
        val item: Any
    )
}

然后在适配器中

@FromJson fun fromJson(item: ScheduleItem.ScheduleItemJson): ScheduleItem<Any> {
    val moshi: Moshi = Moshi.Builder().build()
    val json = moshi.adapter(Map::class.java).toJson(item.item as Map<*, *>)

    return ScheduleItem(
        item.date,
        item.type,
        item.schedule_item_groups ?: listOf(),
        when (item.type) {
            ItemType.GAME -> moshi.adapter(GameItem::class.java).fromJson(json)
            ItemType.EVENT -> moshi.adapter(EventItem::class.java).fromJson(json)
            ItemType.CHECK_IN, ItemType.CHECK_OUT ->
                moshi.adapter(ReservationItem::class.java)
                     .fromJson(json).apply { this!!.type = item.type }
            else -> ScheduleItem.NullItem()
        }!!
    )
}

when语句创建 并将其传递给ScheduleItem构造函数。

 类似资料:
  • 好了,我有了以下Json POJO: > 基于JProduct内部的某些值 JCategory two列表将合并为1,其中将包含更多的JCategory加上prod1/prod2。 根据Moshi的说法,这是映射适配器中数据的有效和高效的方法吗? 注意,我有一个JCategory,并且在同一个对象的列表中,所以我认为适配器会自动解析它,但它没有。所以我尝试了并成功了。 所以我的问题是: 是处理这种

  • 我很难解析JSON的某些内部部分(使用Moshi),这些内部部分可能变化很大,并且高度非结构化。总体看来是: 和数据类结构如下所示: “DataItem”的模式变化很大。看起来Moshi codegen支持适配器,可能允许手动解析这些内部数据类,但我没有找到正确的教程或示例。理想情况下,我希望解析整个响应,就像解析一个定义良好的JSON一样。 以下是我如何使用改装/摩什 我如何实现这一点?任何示例

  • 在为Android项目配置Kotlin之后,我编写了一个简单的。它调用了reverfit来获得一个包含以下数据的JSON文件: 现在我想使用Moshi将JSON数据转换为Kotlin的类,所以下面是反映上述JSON结构的两个类: 和Moshi的自定义类型适配器: 当它进入函数时,就像预期的那样。但奇怪的是,是,应该是。 我对莫希和科特林是新的,我已经在这个问题上坚持了大约10个小时。请帮帮我。谢谢

  • 问题内容: 为什么以下代码无法编译? 错误是 java:不兼容的类型:无法转换为 但我不明白为什么不捕获通配符。 问题答案: 这里的子类型关系为: (我在回答“无法从转换List<List>为List<List<?>>”中解释了这一点。) 因此,基本上它不会编译,因为它是横向转换。 如果可能的话,您可以执行我在那边描述的转换: 如果您无法进行转换,则可能只需要处理raw bound即可。主要由于警

  • 改型异步请求是用两个方法onResponse()和onFailure()回调的。 我还想使用Gson转换器来转换改型响应,然后用APIPesponse包装它。 如果我用like 好像不起作用。不能将json响应数据解析到结果对象中。 有人能帮助如何让用调用enqueue吗?结果是使用Gson转换器解析json数据内容。 有人能帮我指出这个问题吗?

  • 问题内容: 我试图理解Java泛型,它们似乎很难理解。例如,这很好… …就是这个… … 还有这个 … …但是不能编译: 有人可以用简单的语言解释发生了什么吗? 问题答案: 对于泛型类型,主要要了解的是它们不是协变的。 因此,尽管您可以这样做: 以下内容将无法编译: 这是为了避免您绕过通用类型的情况: 因此,一一讲解您的示例 1个 您的通用方法采用a ,而您采用;(基本上是)。可以分配给类型,并且编