使用@Parcelize注解的RealmList

4

我正在尝试使用Kotlin 1.1.4中添加的新注释@Parcelize,其中包含一个RealmList属性的Realm对象。

@Parcelize
@RealmClass
open class Garage(
        var name: String? = null,
        var cars: RealmList<Car> = RealmList()
) : Parcelable, RealmModel

由于注释不支持 RealmList,而且假设 @Parcelize 是为了避免创建方法,那么如何解决支持RealmList的问题呢?
提前感谢。
1个回答

8

编辑:

利用Type Parcelers和@WriteWith注释的功能,可以创建一个RealmList类型的Parceler,它可以帮助你处理这种场景:

使用以下代码:

fun <T> Parcel.readRealmList(clazz: Class<T>): RealmList<T>?
    where T : RealmModel,
          T : Parcelable = when {
    readInt() > 0 -> RealmList<T>().also { list ->
        repeat(readInt()) {
            list.add(readParcelable(clazz.classLoader))
        }
    }
    else -> null
}

fun <T> Parcel.writeRealmList(realmList: RealmList<T>?, clazz: Class<T>)
    where T : RealmModel,
          T : Parcelable {
    writeInt(when {
        realmList == null -> 0
        else -> 1
    })
    if (realmList != null) {
        writeInt(realmList.size)
        for (t in realmList) {
            writeParcelable(t, 0)
        }
    }
}

您可以像这样定义一个接口:
interface RealmListParceler<T>: Parceler<RealmList<T>?> where T: RealmModel, T: Parcelable {
    override fun create(parcel: Parcel): RealmList<T>? = parcel.readRealmList(clazz)

    override fun RealmList<T>?.write(parcel: Parcel, flags: Int) {
        parcel.writeRealmList(this, clazz)
    }

    val clazz : Class<T>
}

您需要为 RealmList<Car> 创建一个特定的解析器,例如:

object CarRealmListParceler: RealmListParceler<Car> {
    override val clazz: Class<Car>
        get() = Car::class.java
}

但是现在,你可以做到以下几点:
@Parcelize
@RealmClass
open class Garage(
        var name: String? = null,
        var cars: @WriteWith<CarRealmListParceler> RealmList<Car> = RealmList()
) : Parcelable, RealmModel

And

@Parcelize
@RealmClass
open class Car(
    ..
): RealmModel, Parcelable {
    ...
}

这样你就不需要手动编写Parceler逻辑。

原始回答:

以下应该可以工作:

@Parcelize
open class Garage: RealmObject(), Parcelable {
    var name: String? = null
    var cars: RealmList<Car>? = null

    companion object : Parceler<Garage> {
        override fun Garage.write(parcel: Parcel, flags: Int) {
            parcel.writeNullableString(name)
            parcel.writeRealmList(cars)
        }

        override fun create(parcel: Parcel): Garage = Garage().apply {
            name = parcel.readNullableString()
            cars = parcel.readRealmList()
        }
    }
}

只要您也添加以下扩展功能:
inline fun <reified T> Parcel.writeRealmList(realmList: RealmList<T>?)
    where T : RealmModel,
          T : Parcelable {
    writeInt(when {
        realmList == null -> 0
        else -> 1
    })
    if (realmList != null) {
        writeInt(realmList.size)
        for (t in realmList) {
            writeParcelable(t, 0)
        }
    }
}

inline fun <reified T> Parcel.readRealmList(): RealmList<T>?
    where T : RealmModel,
          T : Parcelable = when {
    readInt() > 0 -> RealmList<T>().also { list ->
        repeat(readInt()) {
            list.add(readParcelable(T::class.java.classLoader))
        }
    }
    else -> null
}

同时也

fun Parcel.writeNullableString(string: String?) {
    writeInt(when {
        string == null -> 0
        else -> 1
    })
    if (string != null) {
        writeString(string)
    }
}

fun Parcel.readNullableString(): String? = when {
    readInt() > 0 -> readString()
    else -> null
}

太棒了,你太厉害了!我现在正在实现它。我只有一个问题。我们将无法访问伴生对象中的“cars”或“name”变量。如何解决这个问题? - Alexandre Nussbaumer
你需要这样做,因为Parceler给了你Garage.write,否则你就要创建一个新的实例(我之前有一次复制粘贴错误)- 但是我刚刚意识到,我可能还可以使用Parceler<RealmList<T>>@WriteWith<RealmListParceler>()来改进这个答案 - 假设我能让它的泛型工作,无论如何。 - EpicPandaForce
非常感谢,你真是太棒了。它像魔法一样正常工作! - Alexandre Nussbaumer
@AlexandreNussbaumer 谢谢您接受了,不过这样需要编写Parcelable实现代码(尽管更好)。您能否尝试编辑后的答案,如果那也可以的话(在顶部)?我已经花了过去20分钟来尝试它,并且我认为它应该也可以工作。 - EpicPandaForce
1
我重新实现了您的逻辑,现在它可以工作了,我不知道之前为什么无法构建。再次感谢! - Alexandre Nussbaumer
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接