Interview QuestionPractical QuestionFollow-up Questions

Serialization vs Parcelable in Android

skydovesJaewoong Eum (skydoves)||10 min read

Serialization vs Parcelable in Android

Android provides two mechanisms for converting objects into a transferable format: Java's Serializable interface and Android's Parcelable interface. Both enable passing objects between activities, fragments, and services through Intents and Bundles, but they differ fundamentally in how they perform the conversion, what performance characteristics they exhibit, and where each one is appropriate. By the end of this lesson, you will be able to:

  • Explain how Serializable uses reflection to convert objects and why this affects performance.
  • Describe how Parcelable writes data directly to a Parcel without reflection.
  • Compare the garbage collection overhead of both approaches.
  • Identify when Serializable is acceptable despite its performance cost.
  • Apply Kotlin's @Parcelize annotation to eliminate Parcelable boilerplate.

Serializable and Reflection Based Conversion

Serializable is a marker interface from the Java standard library. Implementing it requires no methods. The runtime uses reflection to inspect the object's fields, read their values, and write them to a byte stream:

import java.io.Serializable

data class User(
    val name: String,
    val age: Int
) : Serializable

When Android passes a Serializable object through a Bundle, the system uses ObjectOutputStream to serialize it and ObjectInputStream to deserialize it. During this process, the runtime reflects over every field in the class hierarchy, creates intermediate ObjectStreamClass descriptors, and allocates temporary byte arrays and wrapper objects.

The performance cost comes from two sources. First, reflection is inherently slower than direct field access because the JVM must look up field metadata, check access permissions, and use generic accessor methods instead of typed ones. Second, the serialization process generates a large number of temporary objects that increase garbage collection pressure. On Android, where GC pauses can affect frame rendering, this overhead is measurable on complex object graphs.

Additionally, Serializable processes the entire class hierarchy. If a data class extends another class, ObjectOutputStream walks up the inheritance chain, serializing each level separately. Fields marked as transient are excluded from serialization, which provides a way to skip fields you do not want to persist, but this exclusion mechanism relies on the developer remembering to annotate the correct fields.

Parcelable and Direct Data Writing

Parcelable is an Android specific interface that requires the class to explicitly write its fields to a Parcel and read them back in the same order. No reflection is involved:

import android.os.Parcel
import android.os.Parcelable

data class User(val name: String, val age: Int) : Parcelable {
    override fun writeToParcel(dest: Parcel, flags: Int) {
        dest.writeString(name)
        dest.writeInt(age)
    }

    override fun describeContents(): Int = 0

    companion object CREATOR : Parcelable.Creator<User> {
        override fun createFromParcel(p: Parcel) =
            User(p.readString()!!, p.readInt())
        override fun newArray(size: Int) =
            arrayOfNulls<User>(size)
    }
}

Each writeString() and writeInt() call writes directly to the Parcel's native memory buffer without creating intermediate objects. Reading follows the same order and types, reconstructing the object with minimal allocation. This makes Parcelable significantly faster than Serializable for Android IPC, with benchmarks typically showing an order of magnitude difference for complex objects.

This interview continues for subscribers

Subscribe to Dove Letter for full access to exclusive interviews about Android and Kotlin development.

Become a Sponsor