Joao Alves

Engineering Manager at Skyscanner

Parcelable in Kotlin? Here comes Parcelize

Posted at — Jan 30, 2018

image

Hey everyone, welcome to article number 5 in the series where we’re going to look into how to handle Parcelables in Kotlin. In the previous article we looked into data classes and today we’re going to see how we can have our data classes implementing the Parcelable interface.

The most basic use case for using Parcelable is when we need to pass a model from one activity to another. When passing primitive types is pretty straight forward but when we want to pass our own objects we need to do something to them:

class ActivityA : Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val intent = Intent(this, ActivityB::class.java)dsfasdfsfasdfasdfasdfsahdmfgasdmfhasdh
        val person = Person("name", 32, "email@email.com", 1234)

        intent.putExtra("A_STRING", "some string")
        intent.putExtra("A_NUMBER", 1234)
        intent.putExtra("AN_OBJECT", person) // compilation error

        startActivity(intent)
    }
}

If we consider that the Person object we’re using is the same as in the previous article we get a compilation error on line 11 because we can’t pass our Person model as it is.

image

Our model doesn’t conform to any of the above so we need to do something about it, we have some options:

Implement Serializable: hopefully, you’re not doing this anymore, despite being effective and relatively simple to implement, performance is quite bad since it’s based on reflection.

Json String representation: you can also do this and pass your models as Strings. Again it’s also quite simple to do, specially if you’re already using something like Gson in the project, but again not the best option.

Implement Parcelable: this one is obviously the right answer. It’s the recommended way as per the official documentation. It also works around marshalling/unmarshalling Java objects, like serialization but it’s much more performant.

So, Parcelable is the best option but unfortunately, it involves a lot of boilerplate code that we all have to write and update every time we make changes to our models. In Java if we use AutoValue we can get away from writing and maintaining all that boilerplate code, but what about in Kotlin?

Let’s use our Person model from the previous article then and see how we can implement Parcelable in Kotlin. This is how it looks at the moment if you remember, 1 single line of code.

data class Person(val name: String, val age: Int, val email: String, val phone: Long)

Standard way

First, let’s just go with the standard way and see how it looks in Kotlin. So, if we make our Person model implement the Parcelable interface and ask Android Studio to write down all the required code, this is what we get:

data class Person(val name: String, val age: Int, val email: String, val phone: Long) : Parcelable {
    constructor(parcel: Parcel) : this(
        parcel.readString(),
        parcel.readInt(),
        parcel.readString(),
        parcel.readLong())

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeString(name)
        parcel.writeInt(age)
        parcel.writeString(email)
        parcel.writeLong(phone)
    }

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

Like mentioned before there’s quite a bit of boilerplate code involved. We can run away from writing it initially by using Android Studio to generate the template but we still have to maintain it. We went from 1 line of code to 28 for such a small model. What happens with a more real-life example and anytime we need to add properties? If we wanted to add an address property to our Person model, for example, we would need to at least update the constructor and the writeToParcel methods and add the new field so our model still conforms to the Parcelable implementation.

Parcelize

Here comes Parcelize to the rescue. JetBrains introduced it in the Kotlin 1.1.4 release, so what is it? On their words:

An automatic Parcelable implementation generator. Declare the serialized properties in a primary constructor and add a @Parcelize annotation. writeToParcel()/createFromParcel() methods will be created automatically.

This is an experimental feature at the moment so we need to add the following snippet to our application build.gradle file:

androidExtensions { experimental = true }

This is how our model looks like now:

@Parcelize
data class PersonParcelize(val name: String, 
                           val age: Int, 
                           val email: String, 
                           val phone: Long) : Parcelable

Awesome right? No more Parcelable boilerplate code. All the code needed for the Parcelable implementation is generated by the Annotation Processor and we don’t need to worry about it at all, neither write it in the first place or maintain and update it every time we make changes to our model.

Away with the 28 lines of code and back to a concise and easy to read model. If you ignore the line breaks I did here just for the gist to look good, you could easily have this in 2 lines of code, one for the annotation and another for the class definition.

Once again Kotlin doing an amazing job helping us to get rid of unnecessary boilerplate code. I’m loving this language more and more every day, do you share the feeling? :)

There’s still one small problem with Parcelize though. At the moment there’s an issue with Android Studio showing an error about an incomplete implementation of the Parcelable interface:

image

This is a known bug in the IDE itself and you can ignore it, there’s nothing wrong with the code and it works as expected. You can keep track of the issue here. At the moment it’s In Progress state.

Note: AndroidDeveloperLB mentioned another 2 issues with Parcelize in the 1st comment on the article. One of them affects only version 1.1.4 and the other also 1.1.5. Make sure to update to the latest Kotlin version available to avoid these as well. The 1st one is a bit of an edge case because it happens if you try to use a Serializable object inside a Parcelable and not sure why I would do this.

The second is probably more important as it actually prevents you from installing the app on devices running below Android 4.4 and that is actually more common.

Well, all parcels delivered :) Give some 👏 if you liked the article and as always, please share your ideas and comments. The code is available in the Series Github project (below) under the parcelize package. See you at number 6 👋

Kotlin data classes — enough boilerplate ⇦ PREVIOUS

NEXT ⇨ Kotlin Sealed Classes — enums with swag


comments powered by Disqus