我只是尝试使用 Kotlin 序列化库来替换 Gson,但是在我的模型中将其用于 RealmList 时遇到问题。任何帮助将不胜感激。我收到错误
kotlinx.serialization.SerializationException: Can't locate argument-less serializer for class io.realm.RealmList
我有这样的数据类
data class Person(
var name: String = "",
var social : RealmList<Social> = null,
var id: String = "")
我的社交数据类是
data class Social(
var name: String = "",
var category : String = "",
var id: String = "")
这是我的改造构建器
fun provideRetrofit(okHttpClient: OkHttpClient, urlProvider :
URLProvider): Retrofit {
val contentType = MediaType.get("application/json")
return Retrofit.Builder()
.baseUrl(urlProvider.getApiBaseUrl()!!)
.addConverterFactory(Json.asConverterFactory(contentType))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(okHttpClient)
.build()
}
正在使用特定于 Kotlin 序列化的 Retrofit 适配器 和我的改造电话
override fun loadPersons(): Single<Person> {
return communicationContext.personApi
.getPersonsObservable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnError {
Log.e(TAG, "Load error $it")
}
.doOnSuccess {
Log.e(TAG, "Success size ${it.size}")
}
}
最佳答案
您必须构建一个自定义 RealmListSerializer 才能使其工作。
在 kotlinx.serialization 的当前版本 1.0.1 下,没有可以扩展的 ListSerializer。 这意味着您必须从头开始构建自己的一个。
幸运的是,库中存在某种 ListSerializer,但它被标记为内部,因此无法在代码中访问。
尽管如此,我还是能够根据库中找到的序列化器编写一个序列化器。一切都基于ArrayListSerializer
及其父类。
注意!这些类被标记为实验类。它们的实现很可能会发生变化,这将破坏所有行为。错误是可以预料的。
从中复制的类是 ArrayListSerializer
, ListLikeSerializer
, AbstractCollectionSerializer
包装中kotlinx.serialization.internal.CollectionSerializer.kt
和ArrayClassDesc
, ListLikeDescriptor
包装中kotlinx.serialization.internal.CollectionDescriptors.kt
.
代码如下:RealmListSerializer.kt
import io.realm.RealmList
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.SerialKind
import kotlinx.serialization.descriptors.StructureKind
import kotlinx.serialization.encoding.CompositeDecoder
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
@Serializer(forClass = RealmList::class)
class RealmListSerializer<E>(private val dataSerializer : KSerializer<E>) : KSerializer<RealmList<E>> {
fun builder(): ArrayList<E> = arrayListOf()
private fun ArrayList<E>.toResult() : RealmList<E> {
val realmList = RealmList<E>()
for (i in this) {
realmList.add(i)
}
return realmList
}
private fun merge(decoder: Decoder): RealmList<E> {
val builder = builder()
val startIndex = builder.size
val compositeDecoder = decoder.beginStructure(descriptor)
if (compositeDecoder.decodeSequentially()) {
readAll(compositeDecoder, builder, startIndex, readSize(compositeDecoder, builder))
} else {
while (true) {
val index = compositeDecoder.decodeElementIndex(descriptor)
if (index == CompositeDecoder.DECODE_DONE) break
readElement(compositeDecoder, startIndex + index, builder)
}
}
compositeDecoder.endStructure(descriptor)
return builder.toResult()
}
override val descriptor : SerialDescriptor = RealmListDescriptor(dataSerializer.descriptor)
override fun serialize(encoder : Encoder, value : RealmList<E>) {
val size = value.size
val composite = encoder.beginCollection(descriptor, size)
val iterator = value.iterator()
for (index in 0 until size)
composite.encodeSerializableElement(descriptor, index, dataSerializer, iterator.next())
composite.endStructure(descriptor)
}
override fun deserialize(decoder : Decoder) : RealmList<E> = merge(decoder)
private fun readSize(decoder: CompositeDecoder, builder: ArrayList<E>): Int {
val size = decoder.decodeCollectionSize(descriptor)
builder.ensureCapacity(size)
return size
}
private fun readElement(decoder: CompositeDecoder, index: Int, builder: ArrayList<E>, checkIndex: Boolean = true) {
builder.add(index, decoder.decodeSerializableElement(descriptor, index, dataSerializer))
}
private fun readAll(decoder: CompositeDecoder, builder: ArrayList<E>, startIndex: Int, size: Int) {
require(size >= 0) { "Size must be known in advance when using READ_ALL" }
for (index in 0 until size)
readElement(decoder, startIndex + index, builder, checkIndex = false)
}
}
class RealmListDescriptor(private val elementDescriptor : SerialDescriptor) : SerialDescriptor {
override val kind: SerialKind get() = StructureKind.LIST
override val elementsCount: Int = 1
override fun getElementName(index: Int): String = index.toString()
override fun getElementIndex(name: String): Int =
name.toIntOrNull() ?: throw IllegalArgumentException("$name is not a valid list index")
override fun isElementOptional(index: Int): Boolean {
require(index >= 0) { "Illegal index $index, $serialName expects only non-negative indices"}
return false
}
override fun getElementAnnotations(index: Int): List<Annotation> {
require(index >= 0) { "Illegal index $index, $serialName expects only non-negative indices"}
return emptyList()
}
override fun getElementDescriptor(index: Int): SerialDescriptor {
require(index >= 0) { "Illegal index $index, $serialName expects only non-negative indices"}
return elementDescriptor
}
override val serialName : String
get() = "RealmListSerializer"
}
之后您可以在 RealmObject
中使用此类像这样的类:
@Serializable
open class Person(
@PrimaryKey var id: Long = 0,
var name: String = "",
var age: Int = 0,
@Serializable(with = RealmListSerializer::class)
var dogs: RealmList<Dog> = RealmList()
): RealmObject()
或者,如果您使用大量 RealmList
位于您的 RealmObejct
之一内您可以将此(和其他序列化程序)应用于整个文件。
@file:UseSerializers(RealmListSerializer::class)
再次强调,请谨慎使用。创建的类仍处于实验阶段,可能随时更改,恕不另行通知。
关于android - 用于 ReamList 和 List 的 Kotlin 序列化序列化器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58593010/