(String: {%- set hs_blog_post_body -%} {%- set in_blog_post_body = true -%} <span id="hs_cos_wrapper_post_body" class="hs_cos_wrapper hs_cos_wrapper_meta_field hs_cos_wrapper_type_rich_text" style="" data-hs-cos-general-type="meta_field" data-hs-cos-type="rich_text"> <div class="blog-post__lead h3"> <div> <p>We all have heard about the Parcelable vs Serializable wars, but since the <a href="https://kotlinlang.org/docs/tutorials/android-plugin.html#parcelable-implementations-generator">@Parcelize</a> annotation is going to lose its experimental status any day now, I decided to revisit articles that compare the speed of both these implementations.</p> </div> </div></span>)

Serializable vs Parcelable

Photo of Mariusz Karwowski

Mariusz Karwowski

Updated Feb 9, 2023 • 7 min read
speed

We all have heard about the Parcelable vs Serializable wars, but since the @Parcelize annotation is going to lose its experimental status any day now, I decided to revisit articles that compare the speed of both these implementations.

In almost every single one of them we can clearly see that Parcelable crushes Serializable in terms of speed. But implementing Parcelable always seemed like a lot of additional work. And here comes Kotlin with its magical annotations.

Introduction to @Parcelize

Remember how, whenever you wanted your object to extend from Parcelable, you had to override writeToParcel, create a new constructor, and add a static method named “CREATOR”?

data class CharacterParcelable(
    val id: Int,
    val image: String,
    val name: String,
    val type: String,
    val url: String
) : Parcelable {
    constructor(parcel: Parcel) : this(
        parcel.readInt(),
        parcel.readString()!!,
        parcel.readString()!!,
        parcel.readString()!!,
        parcel.readString()!!
    )
 
    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeInt(id)
        parcel.writeString(image)
        parcel.writeString(name)
        parcel.writeString(type)
        parcel.writeString(url)
    }
 
    override fun describeContents(): Int {
        return 0
    }
 
    companion object {
        @JvmField
        val CREATOR = object : Parcelable.Creator<CharacterParcelable> {
            override fun createFromParcel(parcel: Parcel): CharacterParcelable {
                return CharacterParcelable(parcel)
            }
 
            override fun newArray(size: Int): Array<CharacterParcelable?> {
                return arrayOfNulls(size)
            }
        }
    }
}

Now all you have to do is to add @Parcelize to your class:

@Parcelize
data class CharacterParcelable(
    val id: Int,
    val image: String,
    val name: String,
    val type: String,
    val url: String
) : Parcelable

Speed Test

I wanted testing to be rather simple to remove as many variables that can affect the result as possible.

val bundle = bundleOf()
for (i in 0..TESTS_COUNT) {
    bundle.putParcelable("parcelable$i", parcelable)
}
 
for (i in 0..TESTS_COUNT) {
    bundle.getParcelable<CharacterParcelable>("parcelable$i")
}
 
val bundle = bundleOf()
for (i in 0..TESTS_COUNT) {
    bundle.putSerializable("serializable$i", serializable)
}
 
for (i in 0..TESTS_COUNT) {
    bundle.getSerializable("serializable$i") as CharacterSerializable
}

I ran this test on four different devices with three different TEST_COUNT numbers. Our main contestants today are a Samsung S5 (4.4.2), an LG G3 (5.0.2), a Motorola Moto E2 (6.0) and a Samsung S10 (9.0). The number of iterations for each test were 1_000, 10_000 and 50_000. I repeated each test 10 times to get the best average time result.

With most of the information provided, let us just jump to what everyone is waiting for: data in charts.

1_000 inserts

In the first test, we can see that Parcelable is slower. It’s not not by much, but there is still a difference and the result is surprising.

10_000 inserts

On the other hand, when we increased the number of inserts to bundle, Parcelable became visibly quicker once again - after seeing the previous chart the result is surprising.

50_000 inserts

In the 50_000 inserts chart it’s very surprising that the performance of Samsung S5 has the biggest difference between times and its runtime did not increase as much as that of the LG and the Motorola.

Something Extra

While I was running my test, I thought to myself: what if Kotlin’s auto-generated code creates unnecessary cruft that slows down the process? I added

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}

to my Gradle build file. Maybe it increases the speed of Serializable, so I implemented my own Parcelable and removed JavaVersion 1.8 compatibility and rerun the largest test on the Samsung S10.

50_000 inserts samsung

As you can see, my theory is now confirmed. But to be sure I reran this test once again on the LG G3 and all my hope was gone.

50_000 inserts LG

In Conclusion

As you can see, the question of comparing speed between Serializable and Parcelable cannot be answered with just “Parcelable is faster”. With the growth of the number of iterations, it is clear that Parcelize becomes more efficient. In addition, the differences in speed are more noticeable on older devices. Just remember to always change your approach according to your project’s requirements. Still, personally, I would rather use Parcelize to take advantage of reduced compile time errors from not extending Serialisation interfaces in nested objects. Oh, and I don’t even know what to think about these extra two tests.


LG_G3

Photo of Mariusz Karwowski

More posts by this author

Mariusz Karwowski

Senior Android Developer at Netguru
How to build products fast?  We've just answered the question in our Digital Acceleration Editorial  Sign up to get access

We're Netguru!

At Netguru we specialize in designing, building, shipping and scaling beautiful, usable products with blazing-fast efficiency
Let's talk business!

Trusted by: