How to pass object between Activities with Android Parcelable Android 28.02.2017

Android Parcelable

Android developers often face a predicament while passing object references to activities of whether to go with the Java Serialization method or opt for Android Parcelable.

Passing primitive data types like string, integer, float, etc. through intents is quite easy in Android. All you have to do is put the data with unique key in intents and send it to another activity. Example of passing primitive data types

// inside first activity
Intent intent = new Intent(MainActivity.this, DetailActivity.class);
intent.putExtra("title", "The Godfather");
intent.putExtra("year", 1972);

// inside second activity
Intent intent = getIntent();
String title = intent.getStringExtra("title");
Integer year = intent.getIntExtra("year"); 

If a user wants to send Java objects through intent, Java class should be implemented using the Parcelable interface.

Serialization, on the other hand, is is converting data from a fast, efficient, internal representation to something that can be kept in a persistent store or transmitted over a network. Converting data to its serialized form is often called marshaling it. Converting it back to its live, in-memory representation is called deserializing or unmarshaling.

Parcel is a serialization mechanism provided by Android. In order to write an object to a Parcel, that object should implement the interface Parcelable.

In order to define a custom parcelable class, we need to implement the interface Parcelable in the class and it must override the methods describeContents() and writeToParcel(Parcel dest, int flags). It is also necessary to create a public static member variable CREATOR that should implement the interface Parcelable.Creator<T>. Parcelable requires this method to bind everything together.

Differences between Parcelable and Serialization are often cited around implementation techniques and performance results. There are some comparison Parcelable vs Serialization:

  • Parcelable is well documented in the Android SDK; serialization on the other hand is available in Java. It is for this very reason that Android developers prefer Parcelable over the Serialization technique.
  • In Parcelable, developers write custom code for marshaling and unmarshaling so it creates less garbage objects in comparison to Serialization. The performance of Parcelable over Serialization dramatically improves (around ten times faster), because of this custom implementation.
  • Serialization is a marker interface, which implies the user cannot marshal the data according to their requirements. In Serialization, a marshaling operation is performed on a Java Virtual Machine (JVM) using the Java reflection API. This helps identify the Java objects member and behavior, but also ends up creating a lot of garbage objects. Due to this, the Serialization process is slow in comparison to Parcelable.

The simplest way to create a Parcelable is to use a third-party library called Parceler. By annotating your Java classes that you intend to use, the library is able to create much of the boilerplate code needed as discussed in the manual steps below.

Also you can build Parcelable using parcelabler.com. Just paste simple POJO class and click Build.

public class Movie {
    private String title;
    private int year;

    public Movie(String title, int year) {
        this.title = title;
        this.year = year;
    }
}

Create a Parcelable class in the file Movie.java

public class Movie implements Parcelable {
    String title;
    int year;

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

    // Storing the Movie data to Parcel object
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(title);
        dest.writeInt(year);
    }

    // A constructor that initializes the Movie object
    public Movie(String title, int year) {
        this.title = title;
        this.year = year;
    }

    /**
    * Retrieving Movie data from Parcel object
    * This constructor is invoked by the method createFromParcel(Parcel source) of
    * the object CREATOR
    **/
    private Movie(Parcel in){
        this.title = in.readString();
        this.year = in.readInt();
    }

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

        @Override
        public Movie[] newArray(int size) {
            return new Movie[size];
        }
    };
}

We can now pass the parcelable data between activities within an intent

// somewhere inside an Activity
Movie movie = new Movie("The Godfather", 1972);
Intent i = new Intent(this, DetailActivity.class);
i.putExtra("movie", movie); 
startActivity(i); 

and then access the data in the DetailActivity using:

public class DetailActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Movie movie = (Movie) getIntent().getParcelableExtra("movie");
        if (movie != null) {
            tvTitle.setText("Title: " + movie.title);
            tvYear.setText("Year: " + Integer.toString(movie.year));
        } 
    }
}

Different between Parcelable and Serializable

Serializable is a marker interface that is why there is no method to implement. Using Serializable is easier than Parcelable. Developer need not to write much code when they use Serializable and even code looks cleaner. Still google recommend to use Parcelable instead of Serializable. Why?

Different between Parcelable and Serializable

  • Serializable use reflection that is why it is a slow process.
  • Serializable creates a lot of temporary objects and cause quite a bit of garbage collection.

Conclusion, Parcelable is faster and uses less memory but it requires bit coding and time. Whereas Serialization needs less coding and quick to implement but it is slower and consumes more memory.

Parceler

In Android, Parcelables are a great way to serialize Java Objects between Contexts. Compared with traditional Serialization, Parcelables take on the order of 10x less time to both serialize and deserialize. There is a major flaw with Parcelables, however. Parcelables contain a ton of boilerplate code. To implement a Parcelable, you must mirror the writeToParcel() and createFromParcel() methods such that they read and write to the Parcel in the same order. Also, a Parcelable must define a public static final Parcelable.Creator CREATOR in order for the Android infrastructure to be able to leverage the serialization code.

Parceler is a code generation library that generates the Android Parcelable boilerplate source code. No longer do you have to implement the Parcelable interface, the writeToParcel() or createFromParcel() or the public static final CREATOR. You simply annotate a POJO with @Parcel and Parceler does the rest. Because Parceler uses the Java JSR-269 Annotation Processor, there is no need to run a tool manually to generate the Parcelable code. Just annotate your Java Bean, compile and you are finished. By default, Parceler will serialize the fields of your instance directly.

Following is example of how to pass list of objects between activities.

Movie class.

@Parcel
public class Movie {
    public int id;
    public String name;
    public int year;

    public Movie() {}

    public Movie(String name, int year) {
        this.name = name;
        this.year = year;
    }

    public String getName() {
        return name;
    }

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

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    @Override
    public String toString() {
        return "Movie{" +
                "name='" + name + '\'' +
                ", year=" + year +
                '}';
    }
}

FirstActivity class.

public class FirstActivity extends AppCompatActivity  {
    List<Movie> movies;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);

        Movie m1 = new Movie("Movie 1", 2001);
        Movie m2 = new Movie("Movie 2", 2002);
        Movie m3 = new Movie("Movie 3", 2003);

        movies = new ArrayList<>(Arrays.asList(m1, m2, m3));        
    }

    public void startSecondActivity(View v) {
        Intent i = new Intent(this, SecondActivity.class);
        Bundle bundle = new Bundle();
        bundle.putParcelable("MOVIE_PARCEL", Parcels.wrap(m));
        i.putExtra("MOVIE_EXTRA", bundle);
        startActivity(i);        
    }
}

SecondActivity class.

public class SecondActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        Intent i = getIntent();
        Bundle b = i.getBundleExtra("MOVIE_EXTRA");

        List<Movie> movies = Parcels.unwrap(b.getParcelable("MOVIE_PARCEL"));
        Log.d("TAG", "Movies: " + movies);
    }
}

Useful links