Android Development
Parcelable
Custom Objects
Android Programming
Serialization

How can I make my custom objects Parcelable?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Android uses the Parcelable interface to serialize objects for inter-process communication and to pass data between Activities, Fragments, and Services through Bundle and Intent extras. Unlike Java's Serializable, Parcelable avoids reflection and is significantly faster on Android. This article covers the Kotlin @Parcelize annotation, manual Java implementation, handling nested objects, and best practices for safe parceling.

Kotlin with @Parcelize

The kotlin-parcelize Gradle plugin generates the Parcelable boilerplate at compile time. You annotate a data class with @Parcelize and implement the Parcelable interface.

First, enable the plugin in your module-level build file.

kotlin
1// build.gradle.kts
2plugins {
3    id("com.android.application")
4    id("org.jetbrains.kotlin.android")
5    id("kotlin-parcelize")
6}

Then define your data class.

kotlin
1import android.os.Parcelable
2import kotlinx.parcelize.Parcelize
3
4@Parcelize
5data class Person(
6    val id: Long,
7    val name: String,
8    val email: String,
9    val isActive: Boolean
10) : Parcelable

The compiler generates writeToParcel() and CREATOR automatically. Every property in the primary constructor is parceled in declaration order.

Passing Parcelable Objects Between Activities

Once your class implements Parcelable, you can put it into an Intent or Bundle.

kotlin
1// Sending
2val person = Person(1L, "Alice", "[email protected]", true)
3val intent = Intent(this, DetailActivity::class.java)
4intent.putExtra("person_key", person)
5startActivity(intent)
6
7// Receiving (API 33+)
8val person = intent.getParcelableExtra("person_key", Person::class.java)
9
10// Receiving (pre-API 33, deprecated but still functional)
11@Suppress("DEPRECATION")
12val person = intent.getParcelableExtra<Person>("person_key")

On API 33 and above, the type-safe getParcelableExtra(key, clazz) overload is preferred because it avoids unchecked cast warnings and is more explicit about the expected type.

Handling Nested Parcelable Objects

When a class contains another custom object, that nested object must also implement Parcelable.

kotlin
1@Parcelize
2data class Address(
3    val street: String,
4    val city: String,
5    val zipCode: String
6) : Parcelable
7
8@Parcelize
9data class Person(
10    val id: Long,
11    val name: String,
12    val address: Address,
13    val tags: List<String>
14) : Parcelable

The @Parcelize plugin handles List, Map, Set, and other standard collections automatically, as long as the element types are themselves parcelable or primitive types.

Manual Java Implementation

In Java, you implement Parcelable by writing writeToParcel() to serialize fields and a CREATOR factory to deserialize them. The field order must match exactly between the two methods.

java
1import android.os.Parcel;
2import android.os.Parcelable;
3
4public class Person implements Parcelable {
5    private final long id;
6    private final String name;
7    private final String email;
8    private final boolean isActive;
9
10    public Person(long id, String name, String email, boolean isActive) {
11        this.id = id;
12        this.name = name;
13        this.email = email;
14        this.isActive = isActive;
15    }
16
17    // --- Parcelable write ---
18    @Override
19    public void writeToParcel(Parcel dest, int flags) {
20        dest.writeLong(id);
21        dest.writeString(name);
22        dest.writeString(email);
23        dest.writeByte((byte) (isActive ? 1 : 0));
24    }
25
26    @Override
27    public int describeContents() {
28        return 0;
29    }
30
31    // --- Parcelable read ---
32    protected Person(Parcel in) {
33        id = in.readLong();
34        name = in.readString();
35        email = in.readString();
36        isActive = in.readByte() != 0;
37    }
38
39    public static final Creator<Person> CREATOR = new Creator<Person>() {
40        @Override
41        public Person createFromParcel(Parcel in) {
42            return new Person(in);
43        }
44
45        @Override
46        public Person[] newArray(int size) {
47            return new Person[size];
48        }
49    };
50
51    // Getters omitted for brevity
52}

The writeByte/readByte pattern is the standard way to parcel booleans because Parcel does not have writeBoolean/readBoolean methods on older API levels. On API 29+, writeBoolean and readBoolean are available.

Parceling Enum Types

Enums are not directly parcelable, but you can parcel them by name or ordinal.

kotlin
1@Parcelize
2data class Task(
3    val title: String,
4    val priority: Priority
5) : Parcelable
6
7enum class Priority {
8    LOW, MEDIUM, HIGH
9}

With @Parcelize, enums are handled automatically. In manual Java parceling, write the enum's name() as a string and read it back with valueOf().

java
1// Write
2dest.writeString(priority.name());
3
4// Read
5priority = Priority.valueOf(in.readString());

Parcelable vs Serializable

Both interfaces move objects across process boundaries, but they differ in performance and complexity.

kotlin
1// Serializable — zero boilerplate, uses reflection
2data class Item(val id: Int, val name: String) : java.io.Serializable
3
4// Parcelable — more setup, but faster on Android
5@Parcelize
6data class Item(val id: Int, val name: String) : Parcelable

Serializable uses reflection to discover fields at runtime, which creates temporary objects and triggers garbage collection. Parcelable writes directly to a byte buffer with no reflection. Benchmarks consistently show Parcelable is 5-10x faster for typical Android use cases. Prefer Parcelable for any object passed through Intent, Bundle, or Binder transactions.

Common Pitfalls

  • Field order mismatch in manual parceling: The read order in the Parcel constructor must exactly match the write order in writeToParcel(). A mismatch produces corrupted data or crashes with no clear error message.
  • Forgetting to parcel nested objects: If a field is a custom type that does not implement Parcelable, the compiler (with @Parcelize) or runtime (with manual Java) will fail. Every custom type in the object graph must be parcelable.
  • Using Serializable for IPC-heavy paths: Serializable works but is significantly slower due to reflection overhead. Reserve it for non-performance-critical cases like disk persistence.
  • Not handling null fields in manual Java: If a String field can be null, you must write a null indicator byte before the string and check it during reads, or the deserialized value will be incorrect.
  • Exceeding the Binder transaction limit: The maximum Binder transaction size is roughly 1 MB. Parceling large objects (bitmaps, long lists) across Activities can trigger a TransactionTooLargeException. Pass identifiers instead and load data from a shared repository.

Summary

  • Use Kotlin's @Parcelize annotation with the kotlin-parcelize plugin to eliminate boilerplate for data classes.
  • In Java, manually implement writeToParcel() and CREATOR, ensuring read and write field order matches exactly.
  • Nested objects and enums must also implement Parcelable or be handled through string/ordinal conversion.
  • Prefer Parcelable over Serializable for Android IPC because it avoids reflection and runs 5-10x faster.
  • Keep parceled data small to stay within the 1 MB Binder transaction limit; pass identifiers for large datasets.
  • On API 33+, use the type-safe getParcelableExtra(key, clazz) overload instead of the deprecated generic version.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.