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

