【问题标题】:Android: Parse inner unstructured Json with Moshi adaptersAndroid:使用 Moshi 适配器解析内部非结构化 Json
【发布时间】:2019-11-23 06:33:06
【问题描述】:

我无法解析 JSON(使用 Moshi)的一些内部部分,这些部分可能变化很大并且高度非结构化。总体来说是这样的:

response: {
    items: [{
        type: "typeA",
        data: {
            "1563050214700-001": {
                foo: 123 ....
            }
        }
    }, {
        type: "typeB",
        data: {
            "1563050214700-002": {[
                // differs a lot from previous one
                {bar: 123 .... }
            ]}
        }
    }]
}

数据类结构如下:

data class Response(
    val items: Map<String,List<Item?>>?
) {
    data class Item(
        val type: String?,
        val data: Map<String,List<DataItem?>>?
    ) {
        data class DataItem(
            // members highly unstructured
        )
    }
}

“DataItem”的架构变化很大。看起来 Moshi codegen 支持可能允许手动解析这些内部数据类的适配器,但我无法找到正确的教程或示例。理想情况下,我希望解析整个 Response,就像它是定义良好的 JSON 一样。

这是我如何使用改造/moshi

@Provides
@Singleton
@MyApp
fun provideMyAppRetrofit(context: Context, @MyApp okHttpClient: OkHttpClient): Retrofit {
    return Retrofit.Builder()
        .client(okHttpClient)
        .addConverterFactory(MoshiConverterFactory.create())
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .baseUrl(context.getString(R.string.APP_BASE_URL))
        .build()
}

@Provides
@Singleton
fun provideMyAppApiService(@MyApp retrofit: Retrofit): MyAppApiService {
    return retrofit.create(MyAppApiService::class.java)
}

我如何实现这一目标?任何示例或参考实现都会有所帮助。

【问题讨论】:

    标签: android json gson retrofit moshi


    【解决方案1】:

    欢迎来到多态 JSON 解析问题词!

    我们正在编写自己的 JSON 适配器,如下所示:

    internal class CardJsonAdapter(
            moshi: Moshi
    ) : JsonAdapter<Card>() {
    
        private val cardTypeAdapter = moshi.adapter(Card.Type::class.java)
        private val amountsWithActionAdapter = moshi.adapter(AmountsWithActionCard::class.java)
        private val backgroundImageCardAdapter = moshi.adapter(BackgroundImageCard::class.java)
    
        @Suppress("TooGenericExceptionCaught")
        override fun fromJson(reader: JsonReader): Card = try {
    
            @Suppress("UNCHECKED_CAST")
            val jsonMap = reader.readJsonValue() as Map<String, Any?>
            val type = cardTypeAdapter.fromJsonValue(jsonMap["type"])
            createCardWithType(type, jsonMap)
    
        } catch (error: Exception) {
            if (BuildConfig.DEBUG) {
                Log.w("CardJsonAdapter", "Failed to parse card", error)
            }
            // Try not to break the app if we get unexpected data: ignore errors and return a placeholder card instead.
            UnknownCard
        }
    
        override fun toJson(writer: JsonWriter, value: Card?) {
            throw NotImplementedError("This adapter cannot write cards to JSON")
        }
    
        private fun createCardWithType(type: Type?, jsonMap: Map<String, Any?>) = when (type) {
            null -> UnknownCard
            Type.AMOUNTS_WITH_ACTION -> amountsWithActionAdapter.fromJsonValue(jsonMap)!!
            Type.BACKGROUND_IMAGE_WITH_TITLE_AND_MESSAGE -> backgroundImageCardAdapter.fromJsonValue(jsonMap)!!
        }
    }
    

    但是,它不再是必需的。 Moshi 现在支持多态 JSON 解析 - https://proandroiddev.com/moshi-polymorphic-adapter-is-d25deebbd7c5

    【讨论】:

    • 谢谢。但是,在文章的例子中,不同类型的payload有一个字段区分“action”:“talk”,“action”:“stream”等。这种方法在没有这种区分符的情况下是否可以工作,并且纯粹匹配不同的payload架构?
    • 我不这么认为。您必须对所有可能的解析解决方案进行迭代并自己选择正确的。你对BE有影响吗?您能否要求他们为 JSON 添加一些差异化功能?
    • 很遗憾,我无法更改 BE。在任何情况下,您的回复都是有帮助的(关于多态解析),因此将标记为已接受。谢谢!
    【解决方案2】:

    制作自定义适配器

    class YourAdapter {
    
    @FromJson
    fun fromJson(reader: JsonReader, itemsAdapter: JsonAdapter<ItemsResponse>): List<ItemsResponse>? {
        val list = ArrayList<ItemsResponse>()
        if (reader.hasNext()) {
            val token = reader.peek()
            if (token == JsonReader.Token.BEGIN_ARRAY) {
                reader.beginArray()
                while (reader.hasNext()) {
                    val itemResponse = itemsAdapter.fromJsonValue(reader.readJsonValue())
                    itemsResponse?.let {
                        list.add(itemResponse)
                    }
                }
                reader.endArray()
            }
        }
        return list
    }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-03-09
      • 2020-01-10
      • 1970-01-01
      • 2021-04-24
      • 1970-01-01
      • 1970-01-01
      • 2018-04-07
      • 2022-07-28
      • 2022-01-22
      相关资源
      最近更新 更多