Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Kotlin's "@Parcelize" work with non data classes?

Tags:

android

kotlin

I have simple data classes. I mean, they are data classes logically, but not data class, because I need inheritance and other constructors. They only have fields (of basic types Int?, String?, or List<String>?, etc), and constructors.

I need to pass them (all of their fields need to be passed) from Activity to Activity, so I need to make them parcellisable (or is there a better way?). I first created them as data class and just added @Parcelize. Even though there was a warning and red line that said "CREATOR" or something, I could ignore them and the app worked as intended.

But, now for the reasons above, I changed them to normal classes, and suddenly there is a compilation error.

Error:java.util.NoSuchElementException: Collection contains no element matching the predicate.
    at org.jetbrains.kotlin.android.parcel.ParcelableCodegenExtension.getPropertiesToSerialize(ParcelableCodegenExtension.kt:374)
    ....too long...
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

Error:Execution failed for task ':app:kaptGenerateStubsDebugKotlin'. Internal compiler error. See log for more details

How can I solve this problem? Should I use data class? But I need to parse a JSON object to create them. The classes look like these (not actual classes, but simplified for illustration purposes). Is there a better way than implementing that boring, bulky parcellable code by hand?

@Parcelize
open class Dog():Parcelable
{
    var someField1;
    var someField2;
    constructor(data:JSON):this()
    {
       //parse data to set the fields.
    }
}

@Parcelize
class Doge:Dog
{
    var someField3;
    var someField4;

    constructor():super(); //I do not use it, but for parcellable
    constructor(data:JSON):super(data)
    {
       //parse data to set the fields.
    }
}

PS. I had to switch to PaperParcel. It was very similar to Kotlin's, but it did not require a primary constructor. It only required the same thing to be any constructor, so I could just create a secondary constructor with the same argument names as those of fields, and it worked. Although, I wonder why the CREATOR could not be created automatically.

For example,

@PaperParcel
class Doge:Dog
{
    var someField3;
    var someField4;

    //Needed only for PaperParcel
    constructor(someField3, someField4)
    {
       this.someField3 = someField3;
       this.someField4 = someField4;
    }
    companion object
    {
        @JvmField val CREATOR = PaperParcelDoge.CREATOR
    }
    //end of PaperParcel stuff.

    constructor(data:JSON):super(data)
    {
       //parse data to set the fields.
    }
}
like image 449
Damn Vegetables Avatar asked Jan 25 '18 06:01

Damn Vegetables


People also ask

How do you Parcelize a data class?

There are 3 ways you can make your class Parcelable: Implementing the Parcelable interface and defining the serialization yourself (The traditional way) Using Android Studio plugins, like Android Parcelable code generator. Using annotation-based libraries, like Parceler.

How do I use Parcelize annotations?

Usage. Just add the @Parcelize annotation to a class implementing the Parcelable interface and the Parcelable implementation will be generated automatically. This is the same example as in the previous article, in just 2 lines of code. The class can be a data class but it's optional.

What is Parcelize?

The Android's Parcelable is an interface on which, the values can be written and read from a Parcel. The implementation of the Parcelable interface allows an object to be passed between the different Android components like, activity and fragment.


1 Answers

As stated here, your properties should be declared inside your primary constructor.

Parcelable support

Android Extensions plugin now includes an automatic Parcelable implementation generator. Declare the serialized properties in a primary constructor and add a @Parcelize annotation, and writeToParcel()/createFromParcel() methods will be created automatically:

@Parcelize
class User(val firstName: String, val lastName: String) : Parcelable
like image 92
Benjamin Avatar answered Oct 08 '22 16:10

Benjamin