如何在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
相关产品推荐
相关产品推荐

