You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Android中用Kotlinx Serialization解码URL查询参数并反序列化到数据类?

使用Kotlinx Serialization解码URL查询参数为Kotlin对象

Kotlinx Serialization本身没有提供直接解码URL查询参数的工具,但可以通过两种方式实现需求:

方法一:转JSON后解码(简单易实现)

利用Android的Uri解析URL提取查询参数,将其构建为JSON对象,再通过Kotlinx Serialization的Json解码器转换为目标对象。

步骤1:添加依赖

在Module级别的build.gradle中引入Kotlinx Serialization核心库:

dependencies {
    implementation "org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.0"
}

步骤2:实现解码逻辑

import android.net.Uri
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put

@Serializable
data class MyRecord(
    val title: String,
    val description: String
)

fun decodeUrlToMyRecord(url: String): MyRecord {
    val uri = Uri.parse(url)
    // 构建包含查询参数的JSON对象
    val jsonObject = buildJsonObject {
        uri.queryParameterNames.forEach { paramName ->
            uri.getQueryParameter(paramName)?.let { paramValue ->
                put(paramName, paramValue)
            }
        }
    }
    // 解码为MyRecord对象
    return Json.decodeFromString(jsonObject.toString())
}

// 使用示例
val targetUrl = "https://example.com?title=My+Title&description=My+Description"
val myRecord = decodeUrlToMyRecord(targetUrl)
// 输出 MyRecord(title=My Title, description=My Description)

方法二:自定义解码器(高效灵活)

通过实现Kotlinx Serialization的Decoder接口,直接从查询参数的Map中解码,避免JSON转换的开销,适合复杂数据结构场景。

实现自定义解码器及解码逻辑

import android.net.Uri
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.CompositeDecoder
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.serializer

@Serializable
data class MyRecord(
    val title: String,
    val description: String
)

class QueryParamDecoder(private val paramMap: Map<String, String>) : Decoder {
    override val serializersModule = kotlinx.serialization.modules.EmptySerializersModule

    override fun decodeBoolean(): Boolean = paramMap[decodeElementIndex(serializer<Boolean>().descriptor)]?.toBoolean() ?: false
    override fun decodeByte(): Byte = paramMap[decodeElementIndex(serializer<Byte>().descriptor)]?.toByte() ?: 0
    override fun decodeChar(): Char = paramMap[decodeElementIndex(serializer<Char>().descriptor)]?.first() ?: '\u0000'
    override fun decodeDouble(): Double = paramMap[decodeElementIndex(serializer<Double>().descriptor)]?.toDouble() ?: 0.0
    override fun decodeFloat(): Float = paramMap[decodeElementIndex(serializer<Float>().descriptor)]?.toFloat() ?: 0.0
    override fun decodeInt(): Int = paramMap[decodeElementIndex(serializer<Int>().descriptor)]?.toInt() ?: 0
    override fun decodeLong(): Long = paramMap[decodeElementIndex(serializer<Long>().descriptor)]?.toLong() ?: 0L
    override fun decodeShort(): Short = paramMap[decodeElementIndex(serializer<Short>().descriptor)]?.toShort() ?: 0
    override fun decodeString(): String = paramMap[decodeElementIndex(serializer<String>().descriptor)] ?: ""

    override fun decodeEnum(enumDescriptor: SerialDescriptor): Int {
        val enumName = decodeString()
        return enumDescriptor.getElementIndex(enumName)
    }

    override fun decodeNotNullMark(): Boolean = true
    override fun decodeNull(): Nothing? = null

    override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder {
        return object : CompositeDecoder by this {
            override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
                // 遍历数据类字段,找到匹配的查询参数
                for (index in 0 until descriptor.elementsCount) {
                    val fieldName = descriptor.getElementName(index)
                    if (paramMap.containsKey(fieldName)) {
                        return index
                    }
                }
                return CompositeDecoder.DECODE_DONE
            }
        }
    }
}

fun decodeUrlToMyRecord(url: String): MyRecord {
    val uri = Uri.parse(url)
    // 将查询参数转换为键值对Map
    val paramMap = uri.queryParameterNames.associate { name ->
        name to (uri.getQueryParameter(name) ?: "")
    }
    // 使用自定义解码器解码
    return serializer<MyRecord>().decode(QueryParamDecoder(paramMap))
}

// 使用示例
val targetUrl = "https://example.com?title=My+Title&description=My+Description"
val myRecord = decodeUrlToMyRecord(targetUrl)

注意事项

  • Android的Uri.getQueryParameter()会自动处理URL编码(包括将+转换为空格、解码百分号编码字符),无需手动处理。
  • 如果查询参数存在多值(如key=val1&key=val2),getQueryParameter()会返回第一个值,若需处理多值可使用getQueryParameters()获取列表。

内容的提问来源于stack exchange,提问作者Sébastien Dubois

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 22:43:27