How can I make my custom objects Parcelable?
Asked Answered
W

11

353

I'm trying to make my objects Parcelable. However, I have custom objects and those objects have ArrayList attributes of other custom objects I have made.

What would be the best way to do this?

Whaling answered 24/8, 2011 at 20:1 Comment(0)
P
441

You can find some examples of this here, here (code is taken here), and here.

You can create a POJO class for this, but you need to add some extra code to make it Parcelable. Have a look at the implementation.

public class Student implements Parcelable{
        private String id;
        private String name;
        private String grade;

        // Constructor
        public Student(String id, String name, String grade){
            this.id = id;
            this.name = name;
            this.grade = grade;
       }
       // Getter and setter methods
       .........
       .........

       // Parcelling part
       public Student(Parcel in){
           String[] data = new String[3];

           in.readStringArray(data);
           // the order needs to be the same as in writeToParcel() method
           this.id = data[0];
           this.name = data[1];
           this.grade = data[2];
       }

       @Оverride
       public int describeContents(){
           return 0;
       }

       @Override
       public void writeToParcel(Parcel dest, int flags) {
           dest.writeStringArray(new String[] {this.id,
                                               this.name,
                                               this.grade});
       }
       public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
           public Student createFromParcel(Parcel in) {
               return new Student(in); 
           }

           public Student[] newArray(int size) {
               return new Student[size];
           }
       };
   }

Once you have created this class, you can easily pass objects of this class through the Intent like this, and recover this object in the target activity.

intent.putExtra("student", new Student("1","Mike","6"));

Here, the student is the key which you would require to unparcel the data from the bundle.

Bundle data = getIntent().getExtras();
Student student = (Student) data.getParcelable("student");

This example shows only String types. But, you can parcel any kind of data you want. Try it out.

EDIT: Another example, suggested by Rukmal Dias.

Placia answered 24/8, 2011 at 20:22 Comment(8)
@Rukmal Dias 10x. In fact, I must edit my answer and add some code, because these links will be no longer active some day in the future.Placia
OP asking how to pass custom objects not regular string. Anyone can pass regular Strings. Could you explain HOW to create it with CUSTOM OBJECTKierkegaard
Do I have to actually implement the encoding/decoding parts if I only send them using LocalBroadcastManager? Is it enough to implement Parcelable and put as extra?Tuck
Why do you use a string array instead of just writing the strings successively?Congeneric
Does the order of the members while creating the string array inside writeToParcel method matter?Jaw
@PrakharMohanSrivastava Yes. If you write this.id = data[1]; this.name = data[0]; , the object will be deserialized with 'id' and 'name' swapped.Placia
Must cast intent.putExtra("student", new Student("1","Mike","6")); to Parcelable -> intent.putExtra("student", ((Parcelable)new Student("1","Mike","6")));, because abmbiguous between Serializable and Parcelable.Pita
Does the public Student(Parcel in) have to be public? Can't it be private?Benelux
N
118

IntelliJ IDEA and Android Studio have plugins for this:

These plugins generate Android Parcelable boilerplate code based on fields in the class.

Plugin demo

Nocturne answered 26/12, 2014 at 11:53 Comment(1)
TIL a new way of doing that stuff, Nice!Hubbell
E
58

1. Import Android Parcelable code generator

enter image description here

2. Create a class

public class Sample {
    int id;
    String name;
}

3. Generate > Parcelable from menu

enter image description here enter image description here

Done.

Eusebiaeusebio answered 24/8, 2015 at 8:7 Comment(2)
For those who don't know where the Browse Repositories dialog is at: File > Settings... > Plugins and click on the Browse repositories... button.Epiphyte
Thank you, helped a lot!Malynda
N
21

How? With annotations.

You simply annotate a POJO with a special annotation and library does the rest.

Warning!

I'm not sure that Hrisey, Lombok, and other code generation libraries are compatible with Android's new build system. They may or may not play nicely with hot swapping code (i.e. jRebel, Instant Run).

Pros:

  • Code generation libraries save you from the boilerplate source code.
  • Annotations make your class beautiful.

Cons:

  • It works well for simple classes. Making a complex class parcelable may be tricky.
  • Lombok and AspectJ don't play well together. [details]
  • See my warnings.

Hrisey

Warning!

Hrisey has a known issue with Java 8 and therefore cannot be used for Android development nowadays. See #1 Cannot find symbol errors (JDK 8).

Hrisey is based on Lombok. Parcelable class using Hrisey:

@hrisey.Parcelable
public final class POJOClass implements android.os.Parcelable {
    /* Fields, accessors, default constructor */
}

Now you don't need to implement any methods of Parcelable interface. Hrisey will generate all required code during preprocessing phase.

Hrisey in Gradle dependencies:

provided "pl.mg6.hrisey:hrisey:${hrisey.version}"

See here for supported types. The ArrayList is among them.

Install a plugin - Hrisey xor Lombok* - for your IDE and start using its amazing features!

enter image description here
* Don't enable Hrisey and Lombok plugins together or you'll get an error during IDE launch.


Parceler

Parcelable class using Parceler:

@java.org.parceler.Parcel
public class POJOClass {
    /* Fields, accessors, default constructor */
}

To use the generated code, you may reference the generated class directly, or via the Parcels utility class using

public static <T> Parcelable wrap(T input);

To dereference the @Parcel, just call the following method of Parcels class

public static <T> T unwrap(Parcelable input);

Parceler in Gradle dependencies:

compile "org.parceler:parceler-api:${parceler.version}"
provided "org.parceler:parceler:${parceler.version}"

Look in README for supported attribute types.


AutoParcel

AutoParcel is an AutoValue extension that enables Parcelable values generation.

Just add implements Parcelable to your @AutoValue annotated models:

@AutoValue
abstract class POJOClass implements Parcelable {
    /* Note that the class is abstract */
    /* Abstract fields, abstract accessors */

    static POJOClass create(/*abstract fields*/) {
        return new AutoValue_POJOClass(/*abstract fields*/);
    }
}

AutoParcel in Gradle build file:

apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'

repositories {
    /*...*/
    maven {url "https://clojars.org/repo/"}
}

dependencies {
    apt "frankiesardo:auto-parcel:${autoparcel.version}"
}

PaperParcel

PaperParcel is an annotation processor that automatically generates type-safe Parcelable boilerplate code for Kotlin and Java. PaperParcel supports Kotlin Data Classes, Google's AutoValue via an AutoValue Extension, or just regular Java bean objects.

Usage example from docs.
Annotate your data class with @PaperParcel, implement PaperParcelable, and add a JVM static instance of PaperParcelable.Creator e.g.:

@PaperParcel
public final class Example extends PaperParcelable {
    public static final PaperParcelable.Creator<Example> CREATOR = new PaperParcelable.Creator<>(Example.class);

    private final int test;

    public Example(int test) {
        this.test = test;
    }

    public int getTest() {
        return test;
    }
}

For Kotlin users, see Kotlin Usage; For AutoValue users, see AutoValue Usage.


ParcelableGenerator

ParcelableGenerator (README is written in Chinese and I don't understand it. Contributions to this answer from english-chinese speaking developers are welcome)

Usage example from README.

import com.baoyz.pg.Parcelable;

@Parcelable
public class User {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

}

The android-apt plugin assists in working with annotation processors in combination with Android Studio.

Nocturne answered 18/12, 2014 at 9:4 Comment(0)
S
8

Create Parcelable class without plugin in Android Studio

implements Parcelable in your class and then put cursor on "implements Parcelable" and hit Alt+Enter and select Add Parcelable implementation (see image). that's it.

enter image description here

Suasion answered 18/4, 2020 at 9:21 Comment(0)
E
7

I have found simplest way to create Parcelable class

enter image description here

Enamour answered 10/3, 2017 at 4:38 Comment(1)
it works well for small data, but if we take complex data this wont workRuth
K
1

It is very easy, you can use a plugin on android studio to make objects Parcelables.

public class Persona implements Parcelable {
String nombre;
int edad;
Date fechaNacimiento;

public Persona(String nombre, int edad, Date fechaNacimiento) {
    this.nombre = nombre;
    this.edad = edad;
    this.fechaNacimiento = fechaNacimiento;
}

@Override
public int describeContents() {
    return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
    dest.writeString(this.nombre);
    dest.writeInt(this.edad);
    dest.writeLong(fechaNacimiento != null ? fechaNacimiento.getTime() : -1);
}

protected Persona(Parcel in) {
    this.nombre = in.readString();
    this.edad = in.readInt();
    long tmpFechaNacimiento = in.readLong();
    this.fechaNacimiento = tmpFechaNacimiento == -1 ? null : new Date(tmpFechaNacimiento);
}

public static final Parcelable.Creator<Persona> CREATOR = new Parcelable.Creator<Persona>() {
    public Persona createFromParcel(Parcel source) {
        return new Persona(source);
    }

    public Persona[] newArray(int size) {
        return new Persona[size];
    }
};}
Knute answered 31/7, 2015 at 15:27 Comment(0)
P
1

I tried to use Parcellable, time was short, So used Gson as below. May be it could help few others...

PersonData personData;
BusinessData businessData;

The above both are model objects. I wanted it to pass to MainActivity.class from LoginActivity.class. Parcellable was not working with huge models and would take time to make changes..So I did this,

startActivity(
    new Intent(LogInActivity.this, MainActivity.class)
    .putExtra("businessData", new Gson().toJson(businessData))
    .putExtra("personData", new Gson().toJson(personData))
);

Retrieve these objects in MainActivity.class

BusinessData businessData = new Gson().fromJson(getIntent().getStringExtra("businessData"), BusinessData.class);
PresonData personData = new Gson().fromJson(getIntent().getStringExtra("personData"), PersonData.class);
Plagiarize answered 30/6, 2022 at 6:50 Comment(1)
I think this is the best answer and Clearer Approach. Thanks +1;Laburnum
I
0

Now you can use Parceler library to convert your any custom class in parcelable. Just annotate your POJO class with @Parcel. e.g.

    @Parcel
    public class Example {
    String name;
    int id;

    public Example() {}

    public Example(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getName() { return name; }

    public int getId() { return id; }
}

you can create an object of Example class and wrap through Parcels and send as a bundle through intent. e.g

Bundle bundle = new Bundle();
bundle.putParcelable("example", Parcels.wrap(example));

Now to get Custom Class object just use

Example example = Parcels.unwrap(getIntent().getParcelableExtra("example"));
Irremediable answered 31/1, 2017 at 7:52 Comment(0)
D
0

Android parcable has some unique things. Those are given bellow:

  1. You have to read Parcel as the same order where you put data on parcel.
  2. Parcel will empty after read from parcel. That is if you have 3 data on your parcel. Then after read 3 times parcel will be empty.

Example: To make a class Parceble it must be implement Parceble. Percable has 2 method:

int describeContents();
void writeToParcel(Parcel var1, int var2);

Suppose you have a Person class and it has 3 field, firstName,lastName and age. After implementing Parceble interface. this interface is given bellow:

import android.os.Parcel;
import android.os.Parcelable;
public class Person implements Parcelable{
    private String firstName;
    private String lastName;
    private int age;

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeString(firstName);
        parcel.writeString(lastName);
        parcel.writeInt(age);
    }

}

Here writeToParcel method we are writing/adding data on Parcel in an order. After this we have to add bellow code for reading data from parcel:

protected Person(Parcel in) {
        firstName = in.readString();
        lastName = in.readString();
        age = in.readInt();
    }

    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];
        }
    };

Here, Person class is taking a parcel and getting data in same an order during writing.

Now during intent getExtra and putExtra code is given bellow:

Put in Extra:

Person person=new Person();
                person.setFirstName("First");
                person.setLastName("Name");
                person.setAge(30);

                Intent intent = new Intent(getApplicationContext(), SECOND_ACTIVITY.class);
                intent.putExtra()
                startActivity(intent); 

Get Extra:

Person person=getIntent().getParcelableExtra("person");

Full Person class is given bellow:

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

public class Person implements Parcelable{
    private String firstName;
    private String lastName;
    private int age;



    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeString(firstName);
        parcel.writeString(lastName);
        parcel.writeInt(age);
    }

    protected Person(Parcel in) {
        firstName = in.readString();
        lastName = in.readString();
        age = in.readInt();
    }

    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];
        }
    };

}

Hope this will help you 
Thanks :)
Duval answered 5/12, 2018 at 11:0 Comment(0)
A
-3

To put: bundle.putSerializable("key",(Serializable) object);

To get: List<Object> obj = (List<Object>)((Serializable)bundle.getSerializable("key"));

Aminta answered 14/10, 2014 at 15:10 Comment(2)
This will lead to ClassCastException if object doesn't implement Serializable.Nocturne
While this code snippet may solve the question, including an explanation really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. Please also try not to crowd your code with explanatory comments, this reduces the readability of both the code and the explanations!Prunella

© 2022 - 2024 — McMap. All rights reserved.