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

如何使用Moshi序列化SparseArray?求适配方案及实现指导

我刚好也处理过类似的需求,给你分享一个完整的SparseArray Moshi适配器实现吧,包含序列化(toJson)和反序列化(fromJson)的完整逻辑,你可以直接参考:

完整的SparseArray Moshi适配器实现

这里提供泛型版本的适配器,复用性更强,当然如果你只需要针对WaterWarningItem的固定版本也可以按需调整:

import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.JsonReader
import com.squareup.moshi.JsonWriter
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import android.util.SparseArray

// 泛型适配器,支持任意类型T的SparseArray
class SparseArrayJsonAdapter<T>(private val elementAdapter: JsonAdapter<T>) : JsonAdapter<SparseArray<T>>() {

    override fun fromJson(reader: JsonReader): SparseArray<T> {
        val sparseArray = SparseArray<T>()
        reader.beginObject()
        while (reader.hasNext()) {
            // 将JSON字符串key转为Int类型
            val key = reader.nextName().toInt()
            // 用对应适配器解析泛型对象
            val value = elementAdapter.fromJson(reader)
            sparseArray.put(key, value)
        }
        reader.endObject()
        return sparseArray
    }

    override fun toJson(writer: JsonWriter, value: SparseArray<T>?) {
        if (value == null) {
            writer.nullValue()
            return
        }
        writer.beginObject()
        // 按SparseArray标准方式遍历键值对
        for (i in 0 until value.size()) {
            val key = value.keyAt(i)
            val item = value.valueAt(i)
            writer.name(key.toString())
            elementAdapter.toJson(writer, item)
        }
        writer.endObject()
    }

    // 让Moshi自动识别泛型类型的工厂类
    companion object Factory : JsonAdapter.Factory {
        override fun create(type: kotlin.reflect.Type, annotations: MutableSet<out Annotation>, moshi: Moshi): JsonAdapter<*>? {
            val rawType = Types.getRawType(type)
            if (rawType == SparseArray::class.java) {
                // 获取SparseArray的泛型参数类型
                val elementType = Types.collectionElementType(type, SparseArray::class.java)
                val elementAdapter = moshi.adapter<Any>(elementType)
                return SparseArrayJsonAdapter(elementAdapter)
            }
            return null
        }
    }
}
如何使用这个适配器

创建Moshi实例时添加适配器工厂即可:

val moshi = Moshi.Builder()
    .add(SparseArrayJsonAdapter.Factory)
    .build()

// 序列化示例
val sparseArray = SparseArray<WaterWarningItem>()
sparseArray.put(0, WaterWarningItem("水位预警1"))
sparseArray.put(2, WaterWarningItem("水位预警3"))

// 获取对应类型的适配器
val adapter = moshi.adapter<SparseArray<WaterWarningItem>>(
    Types.newParameterizedType(SparseArray::class.java, WaterWarningItem::class.java)
)
val json = adapter.toJson(sparseArray)
// 输出JSON格式类似:{"0": {"warningContent": "水位预警1"}, "2": {"warningContent": "水位预警3"}}

// 反序列化示例
val parsedSparseArray = adapter.fromJson(json)
关键细节说明
  • 泛型支持:通过工厂类自动识别SparseArray的泛型参数,同一个适配器可以处理任意类型的SparseArray
  • 空值安全:序列化时先判断SparseArray是否为null,避免空指针异常
  • 正确遍历:SparseArray不能直接用for-in遍历,必须通过size()配合keyAt(i)和valueAt(i)的方式遍历
  • 类型转换:JSON的key都是字符串,反序列化时需要转为Int,如果遇到非合法数字的key会抛出异常,你可以根据需求添加异常捕获逻辑

如果你不需要泛型版本,只想针对WaterWarningItem写固定适配器,也可以简化成这样:

class WaterWarningSparseArrayAdapter : JsonAdapter<SparseArray<WaterWarningItem>>() {
    private val itemAdapter = Moshi.Builder().build().adapter<WaterWarningItem>(WaterWarningItem::class.java)

    override fun fromJson(reader: JsonReader): SparseArray<WaterWarningItem> {
        val sparseArray = SparseArray<WaterWarningItem>()
        reader.beginObject()
        while (reader.hasNext()) {
            val key = reader.nextName().toInt()
            val item = itemAdapter.fromJson(reader)
            sparseArray.put(key, item)
        }
        reader.endObject()
        return sparseArray
    }

    override fun toJson(writer: JsonWriter, value: SparseArray<WaterWarningItem>?) {
        if (value == null) {
            writer.nullValue()
            return
        }
        writer.beginObject()
        for (i in 0 until value.size()) {
            writer.name(value.keyAt(i).toString())
            itemAdapter.toJson(writer, value.valueAt(i))
        }
        writer.endObject()
    }
}

使用时直接添加这个适配器实例即可:

val moshi = Moshi.Builder()
    .add(WaterWarningSparseArrayAdapter())
    .build()

这样应该就能解决你的问题了,你可以根据自己的需求选择合适的版本~

内容的提问来源于stack exchange,提问作者Sparrow318

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:29:23