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:
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