8

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.

user4157124
  • 2,809
  • 13
  • 27
  • 42
frankelot
  • 13,666
  • 16
  • 54
  • 89
  • Why are you trying to use Parcelable objects and Realm? – Orgmir Dec 01 '14 at 16:23
  • 1
    Well, I use Pareclable to preserve objects upon configuration changes (device rotations), and Realm to store objects onto a db – frankelot Dec 01 '14 at 16:33
  • 1
    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. – A. Steenbergen Mar 21 '18 at 08:39

5 Answers5

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.

Community
  • 1
  • 1
Vicky Chijwani
  • 10,191
  • 6
  • 56
  • 79
5

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.

Henrique de Sousa
  • 5,727
  • 49
  • 55
  • But is it a good idea to use parcelable objects to store data? – aleien May 30 '16 at 15:54
  • 1
    refer to this answer: http://stackoverflow.com/questions/8896751/android-store-a-parcelable-object-in-sqlite – Henrique de Sousa Jun 01 '16 at 09:11
  • 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. – behelit Jul 05 '23 at 07:07
  • 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. – Henrique de Sousa Jul 05 '23 at 13:27
  • @behelit instead of immediately voting down an answer, a bit more search effort on your part could be made, don't you agree? – Henrique de Sousa Jul 06 '23 at 09:36
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.

Emanuelez
  • 1,651
  • 10
  • 12
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() {
...
Ricardo
  • 2,086
  • 25
  • 35
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")
Dharman
  • 30,962
  • 25
  • 85
  • 135
Milan Jurkulak
  • 557
  • 3
  • 6