【问题标题】:RealmList with @Parcelize annotation带有 @Parcelize 注释的 RealmList
【发布时间】:2018-03-23 17:51:57
【问题描述】:

我正在尝试将 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 的解决方案是什么?

提前致谢

【问题讨论】:

    标签: android kotlin realm parcelable parceler


    【解决方案1】:

    编辑:

    使用 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&lt;Car&gt; 创建一个特定的 parceler,如下所示:

    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
    

    @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
    }
    

    【讨论】:

    • 太棒了,你太棒了!我现在正在实施。我只是有一个问题。我们将无法访问伴随对象中的carsname 变量。如何解决这个问题?
    • 你这样做是因为 Parceler 给了你Garage.write,否则你正在创建它的一个新实例(我在一秒钟前有一个复制粘贴错误)---但我刚刚意识到I can probably also improve this answer a bit using a Parceler&lt;RealmList&lt;T&gt;&gt; with @WriteWith&lt;RealmListParceler&gt;() - 假设我可以让它通用工作,无论如何
    • 嗯,我似乎无法制作 object RealmListParceler&lt;T&gt;:,因为 &lt;T&gt; 不允许在对象上使用,不确定我是否可以做得更好。
    • 我的意思是你的代码不会编译,因为 parcel.writeRealmList(cars) 中的变量 cars 在伴随对象中是不可访问的。
    • 我再次实现了你的逻辑,它现在可以工作了,我不知道为什么它以前没有构建。再次,非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-16
    • 2016-07-19
    • 1970-01-01
    • 2011-12-11
    相关资源
    最近更新 更多