【问题标题】:kotlin - How to read json data?kotlin - 如何读取 json 数据?
【发布时间】:2021-07-25 20:49:30
【问题描述】:

我希望我的 android 应用从 Google 表格中读取数据。 我已经尝试过了,并得到了下面的响应,

{"items":[{"Company":"Tata","Car":"Nexon","Model":"XZ","Price":1400000,"Range":320,"BatterySize": 30},{"公司":"塔塔","汽车":"Nexon","型号":"XZ+","价格":1500000,"范围":320,"电池尺寸":30}]}

我想做的第一件事是使用“公司”或其他键来获取价值。

我也想过滤,只显示价格低于1500000的所有商品。

这是我从 URL 获取数据的方法

val url = URL("My_URL")

val client = OkHttpClient()

val request = okhttp3.Request.Builder()
    .url(url)
    .get()
    .build()

val response = client.newCall(request).execute()

val responseBody = response.body!!.string()

val jsonArray = JSONObject(responseBody)
val name = jsonArray.getString("items")

println(name)

它打印-> [{"Company":"Tata","Car":"Nexon","Model":"XZ","Price":1400000,"Range":320,"BatterySize":30 },{"公司":"塔塔","汽车":"Nexon","型号":"XZ+","价格":1500000,"范围":320,"电池尺寸":30}]

我猜这不是 List 而是 Sting。无法理解如何处理此字符串。

如果您需要更多信息,请告诉我。

【问题讨论】:

    标签: android json kotlin


    【解决方案1】:

    您可能想尝试kotlinx.serialization,它是 Kotlin 语言的一部分。要在您的 Android 项目中使用它(Groovy 语法,如果您在 Gradle 文件中使用 Kotlin DSL,它会略有不同):

    1. 将此添加到您的顶级 build.gradle:classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"

    2. 在您的模块级 build.gradle 中,添加apply plugin: 'kotlinx-serialization' 或者如果您使用较新的语法,请将kotlinx-serialization 添加到您的plugins {} 块中

    要(反)序列化您的数据,请考虑添加以下帮助程序扩展(注意:此示例使用默认 Json;请参阅下文了解如何配置您自己的实例) :

    import kotlinx.serialization.decodeFromString
    import kotlinx.serialization.encodeToString
    import kotlinx.serialization.json.Json
    
    inline fun <reified T> T.toJson(): String = Json.encodeToString(this)
    
    inline fun <reified T> String.fromJson(): T = Json.decodeFromString(this)
    

    警告:使用默认的Json,如果您的API实际提供的数据与您声明的格式不匹配,您将遇到麻烦,因此您可能需要配置一个Json实例来使用在您的(反)序列化程序中(并为您的数据字段分配默认值):

    val json = Json {
        ignoreUnknownKeys = true
        coerceInputValues = true
        // more config if needed
    }
    

    This article 很好地解释了该配置。

    问:什么时候需要自己配置 Json?
    答:如果您确定您的 API 将始终返回您期望的数据,您最好使用默认的。在所有其他情况下,使用自定义配置是明智的。

    根据您的示例,列表中的单个项目如下所示:

    @Serializable
    data class Item(
        @SerialName("Company") val company: String,
        @SerialName("Car") val car: String,
        @SerialName("Model") val model: String,
        @SerialName("Price") val price: Float,
        @SerialName("Range") val range: Int,
        @SerialName("BatterySize") val batterySize: Int
    )
    

    您还需要一个“持有人”来存放已解析的项目:

    @Serializable
    data class Items(@SerialName("items") val data: List<Item>)
    

    您可以通过以下方式获取数据:

    val url = URL("My_URL")
    val client = OkHttpClient()
    val request = okhttp3.Request.Builder()
        .url(url)
        .get()
        .build()
    
    val response = client.newCall(request).execute()
    val items = response.body!!.string().fromJson<Items>().data
    

    我还想过滤并仅显示价格为的所有商品 小于 1500000。

    当然,您现在可以将任何 List 操作应用于您的数据:

    items.filter { it.price < 1500000 }.forEach { item ->
        println("item $item passed the price filter")
    }
    

    有几点需要注意:

    • 在 Android 上,考虑使用 Retrofit 进行 API 调用。 Jake Wharton 有一个 converter factory,它允许您将 kotlinx.serialization 与 Retrofit 一起使用
    • 避免在生产代码中使用非空断言 (!!),始终使用安全调用 (?) 运算符

    【讨论】:

    • 感谢您的详细回答。还有一个问题,如果用户的互联网没有打开或出现任何此类问题,“我应该在哪里添加异常逻辑以防止应用崩溃?”
    • client.newCall(request).execute() 如果没有连接,则会抛出此错误。请注意,您的代码在执行时会抛出NetworkOnMainThreadException,因为您必须在工作线程上进行任何网络调用。解决这个问题的最简单方法是将代码放入 suspend 函数(协程)或使用 Retrofit。还要使用response.body?.string()?.let { // parse JSON },因为!! 断言会在body 为null 时使您的应用程序崩溃(在发生错误时会发生这种情况)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-26
    相关资源
    最近更新 更多