RealmObject AND Parcelable
Asked Answered
C

5

9

Using Realm for Android I have a class:

public class Entry extends RealmObject implements Parcelable {
    ...
}

Parcelable interface contains methods like describeContents(), writeToParcel() and RealmObjects aren't supposed to have methods other than getters and setters:

Error:(81, 17) error: Only getters and setters should be defined in model classes

How can I make these two work together? Is there a better way than creating an separate class (maybe something like RealmEntry)? Doing so would result in a lot of duplicated code.

Comanchean answered 1/12, 2014 at 15:5 Comment(3)
Why are you trying to use Parcelable objects and Realm?Ribbonfish
Well, I use Pareclable to preserve objects upon configuration changes (device rotations), and Realm to store objects onto a dbComanchean
Wouldn't it make more sense to just requery the database after a configuration change? This might even be faster, considering you are using RealmDB which comes with caching mechanisms.Zeiler
M
6

Now there's a different workaround for that: just implement the RealmModel interface instead of extending from RealmObject:

@RealmClass
public class User implements RealmModel {

}

You can find more information in the Realm Documentation.

Manipulator answered 20/5, 2016 at 16:40 Comment(5)
But is it a good idea to use parcelable objects to store data?Jetsam
refer to this answer: #8897251Manipulator
The link doesn't work and this solution doesn't seem to do anything, why is it marked as the answer? I changed my 'RealmObject' to a 'RealmModel' and it still complains that it's not parcelable.Inexactitude
The link is now updated. Regarding doing "anything", instead of extending an object and inheriting all Realm methods, you will now have to use RealmObject static methods, like /* With the RealmModel interface */ RealmObject.isValid(p); instead of /* With the RealmObject base class */ p.isValid();. Refer to the updated documentation for more information.Manipulator
@Inexactitude instead of immediately voting down an answer, a bit more search effort on your part could be made, don't you agree?Manipulator
I
10

UPDATE May 2016: This is answer is now out-dated unless you already use Parceler. @Henrique de Sousa's solution is much better.


Actually, there is a workaround. You can get the result you want if you're willing to use a third-party library (Parceler) for Parcelable generation. See my answer to this other question, quoted below for convenience.

With Parceler v0.2.16, you can do this:

@RealmClass      // required if using JDK 1.6 (unrelated to Parceler issue)
@Parcel(value = Parcel.Serialization.BEAN, analyze = { Feed.class })
public class Feed extends RealmObject {
    // ...
}

Then, use Parcels.wrap(Feed.class, feed) instead of Parcels.wrap(feed) everywhere, otherwise your app will crash with org.parceler.ParcelerRuntimeException: Unable to create ParcelableFactory for io.realm.FeedRealmProxy.

Idiophone answered 18/4, 2015 at 20:5 Comment(0)
M
6

Now there's a different workaround for that: just implement the RealmModel interface instead of extending from RealmObject:

@RealmClass
public class User implements RealmModel {

}

You can find more information in the Realm Documentation.

Manipulator answered 20/5, 2016 at 16:40 Comment(5)
But is it a good idea to use parcelable objects to store data?Jetsam
refer to this answer: #8897251Manipulator
The link doesn't work and this solution doesn't seem to do anything, why is it marked as the answer? I changed my 'RealmObject' to a 'RealmModel' and it still complains that it's not parcelable.Inexactitude
The link is now updated. Regarding doing "anything", instead of extending an object and inheriting all Realm methods, you will now have to use RealmObject static methods, like /* With the RealmModel interface */ RealmObject.isValid(p); instead of /* With the RealmObject base class */ p.isValid();. Refer to the updated documentation for more information.Manipulator
@Inexactitude instead of immediately voting down an answer, a bit more search effort on your part could be made, don't you agree?Manipulator
E
1

It's not possible at the moment to implement Parcelable on RealmObjects. One solution is to Use two realm files: the default one as your object store and a specialized one for temporary saves for rotations etc.

Eryneryngo answered 3/12, 2014 at 9:34 Comment(0)
Z
0

Solution with Kotlin:

import io.realm.com_labtest_di_model_EntryRealmProxy
import org.parceler.Parcel


@RealmClass
@Parcel(implementations = arrayOf(com_labtest_di_model_EntryRealmProxy::class),
    value = org.parceler.Parcel.Serialization.BEAN,
    analyze = arrayOf(Movie::class))
open class Entry() : RealmObject() {
...
Zipper answered 12/3, 2019 at 12:30 Comment(0)
C
0

Parceler does not work in android x. You can use this:

class ExParcelable @JvmOverloads constructor(data: Any? = null) : Parcelable {
    var cls: String? = null
    var json: String? = null

    init {
        if (data is Parcel) {
            cls = data.readString()
            json = data.readString()
        } else {
            cls = data?.let { it::class.java }?.canonicalName
            json = Gson().toJson(data)
        }
    }

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeString(cls)
        parcel.writeString(json)
    }

    override fun describeContents(): Int {
        return 0
    }

    fun value(): Any? {
        return Gson().fromJson(this.json, Class.forName(this.cls))
    }

    companion object CREATOR : Creator<ExParcelable> {
        override fun createFromParcel(parcel: Parcel): ExParcelable {
            return ExParcelable(parcel)
        }

        override fun newArray(size: Int): Array<ExParcelable?> {
            return arrayOfNulls(size)
        }
    }
}

and :

inline fun <reified T : Any?> Intent.extra(key: String): T? {
    var value = extras?.get(key)
    if (value is ExParcelable) {
        value = value.value()
    } else if (T::class == Uri::class) {
        if (value is String) {
            value = value.toUri()
        }
    } else if (T::class == String::class) {
        if (value is Uri) {
            value = value.toString()
        }
    }
    return value as T?
}

inline fun <reified T : Any?> Intent.extra(key: String, value: T?) {
    when (value) {
        null -> {
            // no op
        }
        is Uri -> putExtra(key, value.toString())
        is Boolean -> putExtra(key, value)
        is BooleanArray -> putExtra(key, value)
        is Byte -> putExtra(key, value)
        is ByteArray -> putExtra(key, value)
        is Char -> putExtra(key, value)
        is CharArray -> putExtra(key, value)
        is Short -> putExtra(key, value)
        is ShortArray -> putExtra(key, value)
        is Int -> putExtra(key, value)
        is IntArray -> putExtra(key, value)
        is Long -> putExtra(key, value)
        is LongArray -> putExtra(key, value)
        is Float -> putExtra(key, value)
        is FloatArray -> putExtra(key, value)
        is Double -> putExtra(key, value)
        is DoubleArray -> putExtra(key, value)
        is Date -> putExtra(key, value)
        is Bundle -> putExtra(key, value)
        is Parcelable -> putExtra(key, value)
        is Serializable -> putExtra(key, value)
        is RealmObject -> putExtra(key, ExParcelable(value.get()))
        else -> putExtra(key, ExParcelable(value))
    }
}

and use it like this:

new Intent().apply{
    extra("test", realmObject)
}

and :

intent.extra("test")
Cilla answered 1/8, 2021 at 13:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.