Is there a convenient way to create Parcelable data classes in Android with Kotlin?

I am currently using the excellent AutoParcel in my Java project, which makes it easy to create Parcelable classes.

Now, Kotlin, which I am considering for my next project, has this concept of data classes that automatically generate the equals, hashCode and toString methods.

Is there a convenient way to make the Kotlin Parcelable data class a convenient way (without manually applying methods)?

+99
android kotlin parcelable
Nov 05 '15 at 18:19
source share
12 answers

Kotlin 1.1.4 released

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

@Parcelize class User(val firstName: String, val lastName: String) : Parcelable 

Therefore, you need to enable them by adding build.gradle to your module:

 apply plugin: 'org.jetbrains.kotlin.android.extensions' android { androidExtensions { experimental = true } } 
+148
Aug 15 '17 at 18:12
source share

You can try this plugin:

android-parcelable-intellij-plugin-kotlin

This will help you generate Android Parcelable boilerplate code for the kotlin data class. And this, in the end, looks like this:

 data class Model(var test1: Int, var test2: Int): Parcelable { constructor(source: Parcel): this(source.readInt(), source.readInt()) override fun describeContents(): Int { return 0 } override fun writeToParcel(dest: Parcel?, flags: Int) { dest?.writeInt(this.test1) dest?.writeInt(this.test2) } companion object { @JvmField final val CREATOR: Parcelable.Creator<Model> = object : Parcelable.Creator<Model> { override fun createFromParcel(source: Parcel): Model{ return Model(source) } override fun newArray(size: Int): Array<Model?> { return arrayOfNulls(size) } } } } 
+45
Dec 30 '15 at 6:50
source share

Have you tried PaperParcel ? This is an annotation processor that automatically generates an Android Parcelable template for you.

Application:

Annotate your data class using @PaperParcel , implement PaperParcelable and add a static JVM instance of the generated CREATOR for example.

 @PaperParcel data class Example( val test: Int, ... ) : PaperParcelable { companion object { @JvmField val CREATOR = PaperParcelExample.CREATOR } } 

Your data class is Parcelable and can be passed directly to the Bundle or Intent

Edit: Update using the latest API

+19
Feb 03 '16 at 6:23
source share

The best way without any boilerplate code is the Smuggler gradle plugin. All you need to do is just implement the AutoParcelable interface as

 data class Person(val name:String, val age:Int): AutoParcelable 

And it's all. It works for private classes. This plugin also provides compile time checks for all AutoParcelable classes.

UPD 08/17/2017 Now with the Kotlin 1.1.4 plugin and the Kotlin extensions for Android, you can use the @Parcelize annotation. In this case, the above example would look like this:

 @Parcelize class Person(val name:String, val age:Int): Parcelable 

No need for a data modifier. The biggest drawback at the moment is the use of the kotlin-android-extensions plugin, which has many other functions that may be unnecessary.

+15
May 26 '17 at 4:21
source share

Just click on the data keyword of your kotlin data class, then press alt + Enter, select the first option labeled "Add Parceable Implementation"

+14
Mar 22 '18 at 10:17
source share

I will leave my way to do it if it can help someone.

What I do, I have a common Parcelable

 interface DefaultParcelable : Parcelable { override fun describeContents(): Int = 0 companion object { fun <T> generateCreator(create: (source: Parcel) -> T): Parcelable.Creator<T> = object: Parcelable.Creator<T> { override fun createFromParcel(source: Parcel): T = create(source) override fun newArray(size: Int): Array<out T>? = newArray(size) } } } inline fun <reified T> Parcel.read(): T = readValue(T::class.javaClass.classLoader) as T fun Parcel.write(vararg values: Any?) = values.forEach { writeValue(it) } 

And then I create parts like this:

 data class MyParcelable(val data1: Data1, val data2: Data2) : DefaultParcelable { override fun writeToParcel(dest: Parcel, flags: Int) { dest.write(data1, data2) } companion object { @JvmField final val CREATOR = DefaultParcelable.generateCreator { MyParcelable(it.read(), it.read()) } } } 

Which saves me from overriding the template.

+4
Feb 29 '16 at 12:55
source share

Using Android Studio and the Kotlin plugin, I found an easy way to convert my old Java Parcelable with no additional plugins (if all you want to do is turn the new data class into Parcelable , skip to the fourth code snippet).

Say you have a Person class with an entire Parcelable boiler Parcelable :

 public class Person implements Parcelable{ public static final Creator<Person> CREATOR = new Creator<Person>() { @Override public Person createFromParcel(Parcel in) { return new Person(in); } @Override public Person[] newArray(int size) { return new Person[size]; } }; private final String firstName; private final String lastName; private final int age; public Person(String firstName, String lastName, int age) { this.firstName = firstName; this.lastName = lastName; this.age = age; } protected Person(Parcel in) { firstName = in.readString(); lastName = in.readString(); age = in.readInt(); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(firstName); dest.writeString(lastName); dest.writeInt(age); } @Override public int describeContents() { return 0; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public int getAge() { return age; } } 

Start by removing the Parcelable implementation, leaving the old old Java object empty (the properties must be final and set by the constructor):

 public class Person { private final String firstName; private final String lastName; private final int age; public Person(String firstName, String lastName, int age) { this.firstName = firstName; this.lastName = lastName; this.age = age; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public int getAge() { return age; } } 

Then let the Code > Convert Java file to Kotlin File option do its magic:

 class Person(val firstName: String, val lastName: String, val age: Int) 

Convert this to the data class:

 data class Person(val firstName: String, val lastName: String, val age: Int) 

And finally, enable it again in Parcelable . Place your class name and Android Studio will offer you the Add Parcelable Implementation option. The result should look like this:

 data class Person(val firstName: String, val lastName: String, val age: Int) : Parcelable { constructor(parcel: Parcel) : this( parcel.readString(), parcel.readString(), parcel.readInt() ) override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeString(firstName) parcel.writeString(lastName) parcel.writeInt(age) } override fun describeContents(): Int { return 0 } companion object CREATOR : Parcelable.Creator<Person> { override fun createFromParcel(parcel: Parcel): Person { return Person(parcel) } override fun newArray(size: Int): Array<Person?> { return arrayOfNulls(size) } } } 

As you can see, the Parcelable implementation is some automatically generated code added to you data class definition.

Notes:

  • Attempting to convert Java Parcelable directly to Kotlin will not produce the same result with the current version of the Kotlin plugin ( 1.1.3 ).
  • I had to remove some extra curly braces that the current Parcelable code generator Parcelable . There should be a little mistake.

I hope this tip will work for you as well as for me.

+4
Jun 23 '17 at 20:23
source share

Unfortunately, in Kotlin there is no way to place the real field in the interface, so you cannot inherit it from the adapter interface for free: data class Par : MyParcelable

You can look at delegation, but that doesn't help with fields, AFAIK: https://kotlinlang.org/docs/reference/delegation.html

So, the only option I see is the shadow function for Parcelable.Creator , which is obvious.

+3
Nov 05 '15 at 20:34
source share

I prefer to use https://github.com/johncarl81/parceler lib with

 @Parcel(Parcel.Serialization.BEAN) data class MyClass(val value) 
+2
Feb 10 '17 at 9:16
source share

There is a plugin, but it is not always updated as Kotlin develops: https://plugins.jetbrains.com/plugin/8086

Alternative: I have a working example of a custom data class using Parcelable and lists:

Data classes using Parcelable with lists:

https://gist.github.com/juanchosaravia/0b61204551d4ec815bbf

Hope this helps!

0
Dec 12 '15 at 20:51
source share

Thanks to the @Parcel annotation, Kotlin simplified the entire Parcelization process in Android.

For this

Step 1. Add Kotlin extensions to your gradle module module

Step 2. Add experimental = true, as this function is still in experiments in Gradle.

androidExtensions {experimental = true}

Step 3. Announce the data class using @Parcel

Here is a simple example of using @Parcel

0
Jul 22 '18 at 9:04 on
source share
  • Use the @Parcelize annotation on top of your Model / Data class
  • Use the latest version of Kotlin
  • Use the latest version of Kotlin Android Extensions in your application module

Example:

 @Parcelize data class Item( var imageUrl: String, var title: String, var description: Category ) : Parcelable 
0
Jul 24 '19 at 12:27
source share



All Articles